Merge develop in release/testnet (#1688)

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: remove old type gen in positions (#1619)

* chore: remove old type gen

* chore: remove old type gen - small fixes

Co-authored-by: maciek <maciek@vegaprotocol.io>

* chore: replace duplicated assets queries with assetsProvider (#1617)

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Feat/1446: Add UpdateAsset proposal form (#1558)

* Feat/1446: Add UpdateAsset proposal form

* Feat/1446: Formatting fix

* Feat/1446: changes from PR comments

* Feat/1446: Fix for mockWalletContext shape and lint fix

* Feat/1446: Fix more tests reliant on the updated mockPubkey shape change

* Feat/1446: Adding the update asset proposal terms interface into the new location

Co-authored-by: Bartłomiej Głownia <bglownia@gmail.com>
Co-authored-by: Dexter <dexter.edwards93@gmail.com>

* Test/1574 governance proposal forms (#1629)

* chore: remove repeated code from existing test

* test: update parameters added

* test: new proposals added

* chore: tidy forms flow

* test: governance acs added

* chore: revert change in asset json

* chore: remove only tag

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: move generateAccounts to seerate file (#1623)

* chore: rename wallet label to match app, add more user friendly fetch failed message (#1650)

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Adjust workflow to new wallet (#1668)

* chore: change wallet import and fix test

* chore: fix wallet run

* chore: fix wallet run

* chore: update capsule config

* housekeeping: fixes wallet tests (#1669)

* chore: added useYesterday hook (#1635)

* chore: added useYesteday hook

* chore: added useYesterday hook

* fix: remove setting up viewport height to derived from grid  element (#1673)

* feat: updated withdrawal tab (849) (#1579)

* feat: updated withdrawal tab (849)

* added pending table to the token app, added pending completed filtering to the data provider

* amended and added unit tests

* amended time formats

* added units

* fixes errors

* addressed comments

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* feat(explorer): add txs infinite scroll list (#1625)

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* fix: deal ticket estimated uncrossing (#1636)

* fix: invalid uncrossing price

* chore: align estimated uncrossing price with size label

* fix: 0 used balance on margin and bond accounts should not be displayed

* fix: small tweaks and bugfixes

* fix: filter empty acounts

* fix: fix unit test

* fix: fix unit test

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* chore: update tranches

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Test/1633 governance flows (#1683)

* test: refactor most existing tests to use raw proposal

* chore: remove unnecessary waits

* chore: acs updated for token association (#1687)

* Test/block exp network params (#1681)

* test: network parameter tests

* test: lint

* test: add comments

* test: more guidance notes

* test: disable theme check whilst investigating

* test: fix failing test for console lite

* test: attempt 2 to fix console lite error only in CI

* test: lint

* test: remove check

* test: update conflict function

Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: mattrussell36 <mattrussell36@users.noreply.github.com>
Co-authored-by: macqbat <kubat.maciek@gmail.com>
Co-authored-by: maciek <maciek@vegaprotocol.io>
Co-authored-by: Bartłomiej Głownia <bglownia@gmail.com>
Co-authored-by: Sam Keen <samuel@vegaprotocol.io>
Co-authored-by: Dexter <dexter.edwards93@gmail.com>
Co-authored-by: Joe Tsang <30622993+jtsang586@users.noreply.github.com>
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
Co-authored-by: Radosław Szpiech <szpiechrados@gmail.com>
Co-authored-by: Art <artur@vegaprotocol.io>
Co-authored-by: Elmar <102954831+elmar-vega@users.noreply.github.com>
Co-authored-by: AndyWhiteVega <106072061+AndyWhiteVega@users.noreply.github.com>
This commit is contained in:
m.ray
2022-10-10 10:57:18 +01:00
committed by GitHub
co-authored by maciek Bartłomiej Głownia Dexter Matthew Russell mattrussell36 macqbat Sam Keen Joe Tsang Radosław Szpiech Art Elmar AndyWhiteVega
parent 1f8f54617b
commit d1e9cf33a4
170 changed files with 3254 additions and 3160 deletions
+3 -3
View File
@@ -32,14 +32,14 @@ runs:
- name: Import fairground network
shell: bash
if: ${{ inputs.capsule==false }}
run: vegawallet network import --from-url="https://raw.githubusercontent.com/vegaprotocol/networks/master/fairground/fairground.toml" --force --home ~/.vegacapsule/testnet/wallet
run: vegawallet network import --from-url="https://raw.githubusercontent.com/vegaprotocol/networks-internal/master/fairground/vegawallet-fairground.toml" --force --home ~/.vegacapsule/testnet/wallet
- name: Start service using fairground network
shell: bash
if: ${{ inputs.capsule==false }}
run: vegawallet service run --network fairground --automatic-consent --home ~/.vegacapsule/testnet/wallet &
run: vegawallet service run --network fairground --automatic-consent --no-version-check --home ~/.vegacapsule/testnet/wallet &
- name: Start service using capsule network
shell: bash
if: ${{ inputs.capsule }}
if: ${{ inputs.capsule==true }}
run: vegawallet service run --network DV --automatic-consent --home ~/.vegacapsule/testnet/wallet &
@@ -296,11 +296,7 @@ describe('Market trade', { tags: '@smoke' }, () => {
cy.get('#step-3-panel').find('dd').eq(4).should('have.text', ' - ');
cy.getByTestId('place-order').click();
cy.getByTestId('dialog-title').should(
'have.text',
'Awaiting network confirmation'
);
cy.getByTestId('place-order').should('be.enabled').click();
}
});
@@ -8,10 +8,8 @@ import {
emptyPositions,
generateMargins,
} from '../support/mocks/generate-positions';
import {
generateAccounts,
generateAssets,
} from '../support/mocks/generate-accounts';
import { generateAccounts } from '../support/mocks/generate-accounts';
import { generateAssets } from '../support/mocks/generate-assets';
import { generateOrders } from '../support/mocks/generate-orders';
import { generateFills } from '../support/mocks/generate-fills';
import {
@@ -1,6 +1,6 @@
import merge from 'lodash/merge';
import type { AccountsQuery, AssetsQuery } from '@vegaprotocol/accounts';
import { AccountType, Schema as Types } from '@vegaprotocol/types';
import type { AccountsQuery } from '@vegaprotocol/accounts';
import { AccountType } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
export const generateAccounts = (
@@ -75,43 +75,3 @@ export const generateAccounts = (
};
return merge(defaultAccounts, override);
};
export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
const defaultAssets: AssetsQuery = {
assetsConnection: {
edges: [
{
node: {
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
name: 'Euro',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
name: 'DAI',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-0',
symbol: 'AST0',
decimals: 5,
name: 'Asto',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
],
},
};
return merge(defaultAssets, override);
};
@@ -0,0 +1,55 @@
import merge from 'lodash/merge';
import type { AssetsQuery } from '@vegaprotocol/assets';
import { Schema as Types } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
const defaultAssets: AssetsQuery = {
assetsConnection: {
edges: [
{
node: {
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
name: 'Euro',
source: {
__typename: 'ERC20',
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
},
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
name: 'DAI',
source: {
__typename: 'ERC20',
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
},
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-0',
symbol: 'AST0',
decimals: 5,
name: 'Asto',
source: {
__typename: 'BuiltinAsset',
},
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
],
},
};
return merge(defaultAssets, override);
};
@@ -1,14 +1,15 @@
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
import type {
Positions,
Positions_party_positionsConnection_edges_node,
PositionsQuery,
PositionFieldsFragment,
MarginsQuery,
} from '@vegaprotocol/positions';
export const generatePositions = (
override?: PartialDeep<Positions>
): Positions => {
const nodes: Positions_party_positionsConnection_edges_node[] = [
override?: PartialDeep<PositionsQuery>
): PositionsQuery => {
const nodes: PositionFieldsFragment[] = [
{
__typename: 'Position',
realisedPNL: '0',
@@ -47,7 +48,7 @@ export const generatePositions = (
},
];
const defaultResult: Positions = {
const defaultResult: PositionsQuery = {
party: {
__typename: 'Party',
id: Cypress.env('VEGA_PUBLIC_KEY'),
@@ -66,7 +67,7 @@ export const generatePositions = (
return merge(defaultResult, override);
};
export const emptyPositions = () => {
export const emptyPositions = (): PositionsQuery => {
return {
party: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
@@ -76,7 +77,7 @@ export const emptyPositions = () => {
};
};
export const generateMargins = () => {
export const generateMargins = (): MarginsQuery => {
return {
party: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
@@ -119,7 +120,7 @@ export const generateMargins = () => {
},
{
node: {
m_typename: 'MarginLevels',
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
@@ -1,32 +1,12 @@
import { gql, useQuery } from '@apollo/client';
import { useMemo } from 'react';
import { DepositManager } from '@vegaprotocol/deposits';
import { getEnabledAssets, t } from '@vegaprotocol/react-helpers';
import { t } from '@vegaprotocol/react-helpers';
import { enabledAssetsProvider } from '@vegaprotocol/assets';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { Networks, useEnvironment } from '@vegaprotocol/environment';
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { Web3Container } from '@vegaprotocol/web3';
import type { DepositAssets } from './__generated__/DepositAssets';
const DEPOSITS_QUERY = gql`
query DepositAssets {
assetsConnection {
edges {
node {
id
name
symbol
decimals
status
source {
... on ERC20 {
contractAddress
}
}
}
}
}
}
`;
/**
* Fetches data required for the Deposit page
@@ -34,20 +14,19 @@ const DEPOSITS_QUERY = gql`
export const DepositContainer = () => {
const { VEGA_ENV } = useEnvironment();
const { pubKey } = useVegaWallet();
const { data, loading, error } = useQuery<DepositAssets>(DEPOSITS_QUERY, {
variables: { partyId: pubKey },
const variables = useMemo(() => ({ partyId: pubKey }), [pubKey]);
const { data, loading, error } = useDataProvider({
dataProvider: enabledAssetsProvider,
variables,
skip: !pubKey,
});
const assets = getEnabledAssets(data);
return (
<AsyncRenderer<DepositAssets> data={data} loading={loading} error={error}>
{assets.length ? (
<AsyncRenderer data={data} loading={loading} error={error}>
{data && data.length ? (
<Web3Container>
<DepositManager
assets={assets}
assets={data}
isFaucetable={VEGA_ENV !== Networks.MAINNET}
/>
</Web3Container>
@@ -4,6 +4,7 @@ import type { AgGridReact } from 'ag-grid-react';
import {
useScreenDimensions,
useDataProvider,
useYesterday,
} from '@vegaprotocol/react-helpers';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import type { MarketState } from '@vegaprotocol/types';
@@ -33,13 +34,13 @@ const SimpleMarketList = () => {
const statusesRef = useRef<Record<string, MarketState | ''>>({});
const gridRef = useRef<AgGridReact | null>(null);
const yesterday = useYesterday();
const variables = useMemo(() => {
const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600;
return {
since: new Date(yesterday * 1000).toISOString(),
since: new Date(yesterday).toISOString(),
interval: Interval.INTERVAL_I1H,
};
}, []);
}, [yesterday]);
const { data, error, loading } = useDataProvider({
dataProvider: marketsWithCandlesProvider,
variables,
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import classNames from 'classnames';
import { InView } from 'react-intersection-observer';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { useDataProvider, useYesterday } from '@vegaprotocol/react-helpers';
import type { Candle } from '@vegaprotocol/market-list';
import { marketCandlesProvider } from '@vegaprotocol/market-list';
import { Interval } from '@vegaprotocol/types';
@@ -68,13 +68,13 @@ const SimpleMarketPercentChangeWrapper = (props: Props) => {
};
const SimpleMarketPercentChange = ({ candles, marketId, setValue }: Props) => {
const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600;
const yesterday = useYesterday();
const { data } = useDataProvider({
dataProvider: marketCandlesProvider,
variables: {
marketId,
interval: Interval.INTERVAL_I1D,
since: new Date(yesterday * 1000).toISOString(),
since: new Date(yesterday).toISOString(),
},
});
+1 -1
View File
@@ -10,7 +10,7 @@ module.exports = defineConfig({
},
baseUrl: 'http://localhost:3000',
fileServerFolder: '.',
fixturesFolder: false,
fixturesFolder: './src/fixtures',
specPattern: '**/*.cy.{js,jsx,ts,tsx}',
modifyObstructiveCode: false,
supportFile: './src/support/index.js',
@@ -0,0 +1,121 @@
{
"eighteenDecimal": [
"governance.proposal.asset.minProposerBalance",
"governance.proposal.asset.minVoterBalance",
"governance.proposal.freeform.minProposerBalance",
"governance.proposal.freeform.minVoterBalance",
"governance.proposal.market.minProposerBalance",
"governance.proposal.market.minVoterBalance",
"governance.proposal.updateMarket.minProposerBalance",
"governance.proposal.updateMarket.minVoterBalance",
"governance.proposal.updateNetParam.minProposerBalance",
"governance.proposal.updateNetParam.minVoterBalance",
"reward.staking.delegation.maxPayoutPerEpoch",
"reward.staking.delegation.maxPayoutPerParticipant",
"reward.staking.delegation.minimumValidatorStake",
"spam.protection.delegation.min.tokens",
"spam.protection.proposal.min.tokens",
"spam.protection.voting.min.tokens",
"validators.delegation.minAmount"
],
"fiveDecimal": [
"governance.proposal.updateAsset.minProposerBalance",
"governance.proposal.updateAsset.minVoterBalance",
"governance.proposal.updateAsset.requiredParticipation",
"governance.proposal.updateMarket.minProposerEquityLikeShare",
"market.fee.factors.infrastructureFee",
"market.fee.factors.makerFee",
"market.liquidity.bondPenaltyParameter",
"market.liquidity.maximumLiquidityFeeFactorLevel",
"market.liquidity.minimum.probabilityOfTrading.lpOrders",
"market.liquidity.probabilityOfTrading.tau.scaling",
"market.liquidity.stakeToCcySiskas",
"market.liquidity.targetstake.triggering.ratio",
"market.liquidityProvision.minLpStakeQuantumMultiple",
"market.liquidityProvision.shapes.maxSize",
"market.stake.target.scalingFactor",
"network.validators.ersatz.multipleOfTendermintValidators",
"network.validators.ersatz.rewardFactor",
"network.validators.incumbentBonus",
"network.validators.minimumEthereumEventsForNewValidator",
"network.validators.multisig.numberOfSigners",
"network.validators.tendermint.number",
"reward.staking.delegation.competitionLevel",
"reward.staking.delegation.delegatorShare",
"reward.staking.delegation.minValidators",
"reward.staking.delegation.optimalStakeMultiplier",
"reward.staking.delegation.payoutFraction",
"rewards.marketCreationQuantumMultiple",
"spam.pow.difficulty",
"spam.pow.increaseDifficulty",
"spam.pow.numberOfPastBlocks",
"spam.pow.numberOfTxPerBlock",
"spam.protection.max.batchSize",
"spam.protection.max.delegations",
"spam.protection.max.proposals",
"spam.protection.max.votes",
"spam.protection.maxUserTransfersPerEpoch",
"transfer.fee.factor",
"transfer.minTransferQuantumMultiple",
"snapshot.interval.length"
],
"json": [
"blockchains.ethereumConfig",
"market.margin.scalingFactors",
"market.monitor.price.defaultParameters"
],
"percentage": [
"governance.proposal.asset.requiredMajority",
"governance.proposal.asset.requiredParticipation",
"governance.proposal.freeform.requiredMajority",
"governance.proposal.freeform.requiredParticipation",
"governance.proposal.market.requiredMajority",
"governance.proposal.market.requiredParticipation",
"governance.proposal.updateMarket.requiredMajority",
"governance.proposal.updateMarket.requiredMajorityLP",
"governance.proposal.updateMarket.requiredParticipation",
"governance.proposal.updateMarket.requiredParticipationLP",
"governance.proposal.updateNetParam.requiredMajority",
"governance.proposal.updateNetParam.requiredParticipation",
"validators.vote.required"
],
"duration": [
"governance.proposal.asset.maxClose",
"governance.proposal.asset.maxEnact",
"governance.proposal.asset.minClose",
"governance.proposal.asset.minEnact",
"governance.proposal.freeform.maxClose",
"governance.proposal.freeform.minClose",
"governance.proposal.market.maxClose",
"governance.proposal.market.maxEnact",
"governance.proposal.market.minClose",
"governance.proposal.market.minEnact",
"governance.proposal.updateAsset.maxClose",
"governance.proposal.updateAsset.maxEnact",
"governance.proposal.updateAsset.minClose",
"governance.proposal.updateAsset.minEnact",
"governance.proposal.updateMarket.maxClose",
"governance.proposal.updateMarket.maxEnact",
"governance.proposal.updateMarket.minClose",
"governance.proposal.updateMarket.minEnact",
"governance.proposal.updateNetParam.maxClose",
"governance.proposal.updateNetParam.maxEnact",
"governance.proposal.updateNetParam.minClose",
"governance.proposal.updateNetParam.minEnact",
"market.auction.maximumDuration",
"market.auction.minimumDuration",
"market.liquidity.providers.fee.distributionTimeStep",
"market.stake.target.timeWindow",
"market.value.windowLength",
"network.checkpoint.timeElapsedBetweenCheckpoints",
"network.floatingPointUpdates.delay",
"reward.staking.delegation.payoutDelay",
"spam.pow.hashFunction",
"validators.epoch.length"
],
"date": [
"limits.assets.proposeEnabledFrom",
"limits.markets.proposeEnabledFrom"
],
"id": ["reward.asset"]
}
+241 -17
View File
@@ -1,33 +1,257 @@
context('Network parameters page', { tags: '@smoke' }, function () {
before('visit token home page', function () {
cy.visit('/');
before('navigate to network parameter page', function () {
cy.fixture('net_parameter_format_lookup').as('networkParameterFormat');
});
describe('Verify elements on page', function () {
const networkParametersNavigation = 'a[href="/network-parameters"]';
const networkParametersHeader = '[data-testid="network-param-header"]';
const tableRows = '[data-testid="key-value-table-row"]';
beforeEach('Navigate to network parameter page', function () {
before('navigate to network parameter page', function () {
cy.visit('/');
cy.get(networkParametersNavigation).click();
});
it('Network paremeter page is displayed', function () {
verifyNetworkParametersPageDisplayed();
it('should show network parameter heading at top of page', function () {
cy.get(networkParametersHeader)
.should('have.text', 'Network Parameters')
.and('be.visible');
});
it('Network parameter page displayed on mobile', function () {
it('should list each of the network parameters available', function () {
cy.get_network_parameters().then((network_parameters) => {
const numberOfNetworkParametersInSystem =
Object.keys(network_parameters).length;
cy.get(tableRows).should(
'have.length',
numberOfNetworkParametersInSystem
);
});
});
it('should list each network parameter displayed with json - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (this.networkParameterFormat.json.includes(parameterName)) {
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.invoke('text')
.convert_string_json_to_js_object()
.then((jsonOnPage) => {
cy.wrap(parameterValue, { log: false })
.convert_string_json_to_js_object()
.then((jsonInSystem) =>
assert.deepEqual(
jsonOnPage,
jsonInSystem,
`Checking ${parameterName} has the correct value of ${jsonInSystem}`
)
);
});
}
});
});
});
it('should list each network parameter displayed as a percentage - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (this.networkParameterFormat.percentage.includes(parameterName)) {
const formattedPercentageParameter =
(parseFloat(parameterValue) * 100).toFixed(0) + '%';
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.invoke('text')
.then((parameterValueOnPage) => {
assert.equal(
parameterValueOnPage,
formattedPercentageParameter,
`Checking ${parameterName} has the correct value of ${formattedPercentageParameter}`
);
cy.contains(parameterValueOnPage).should('be.visible');
});
}
});
});
});
it('should list each network parameter displayed as an id - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (this.networkParameterFormat.id.includes(parameterName)) {
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.should('contain', parameterValue)
.and('be.visible')
.invoke('text');
}
});
});
});
it('should list each network parameter displayed as a date - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (this.networkParameterFormat.date.includes(parameterName)) {
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.should('contain', parameterValue)
.and('be.visible');
}
});
});
});
it('should list each network parameter displayed as a duration - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (this.networkParameterFormat.duration.includes(parameterName)) {
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.should('contain', parameterValue)
.and('be.visible');
}
});
});
});
it('should list each network parameter displayed as a currency value with four decimals - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (this.networkParameterFormat.fiveDecimal.includes(parameterName)) {
cy.convert_number_to_four_decimal(parameterValue)
.add_commas_to_number_if_large_enough()
.then((parameterValueFormatted) => {
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.invoke('text')
.then((parameterValueOnPage) => {
assert.equal(
parameterValueOnPage,
parameterValueFormatted,
`Checking ${parameterName} has the correct value of ${parameterValueFormatted}`
);
cy.contains(parameterValueOnPage).should('be.visible');
});
});
}
});
});
});
it('should list each network parameter displayed as a currency value with eighteen decimals - in the correct format', function () {
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
const parameterValue = network_parameter[1];
if (
this.networkParameterFormat.eighteenDecimal.includes(parameterName)
) {
cy.convert_number_to_eighteen_decimal(parameterValue)
.add_commas_to_number_if_large_enough()
.then((parameterValueFormatted) => {
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.invoke('text')
.then((parameterValueOnPage) => {
assert.equal(
parameterValueOnPage,
parameterValueFormatted,
`Checking ${parameterName} has the correct value of ${parameterValueFormatted}`
);
cy.contains(parameterValueOnPage).should('be.visible');
});
});
}
});
});
});
it.skip('should be able to switch network parameter page - between light and dark mode', function () {
const whiteThemeSelectedMenuOptionColor = 'rgb(255, 7, 127)';
const whiteThemeJsonFieldBackColor = 'rgb(255, 255, 255)';
const whiteThemeSideMenuBackgroundColor = 'rgb(255, 255, 255)';
const blackThemeSelectedMenuOptionColor = 'rgb(223, 255, 11)';
const blackThemeJsonFieldBackColor = 'rgb(38, 38, 38)';
const blackThemeSideMenuBackgroundColor = 'rgb(0, 0, 0)';
const themeSwitcher = '[data-testid="theme-switcher"]';
const jsonFields = '.hljs';
const sideMenuBackground = '.absolute';
// White Mode
cy.get(themeSwitcher).click();
cy.get(networkParametersNavigation)
.should('have.css', 'background-color')
.and('include', whiteThemeSelectedMenuOptionColor);
cy.get(jsonFields)
.should('have.css', 'background-color')
.and('include', whiteThemeJsonFieldBackColor);
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.and('include', whiteThemeSideMenuBackgroundColor);
// Dark Mode
cy.get(themeSwitcher).click();
cy.get(networkParametersNavigation)
.should('have.css', 'background-color')
.and('include', blackThemeSelectedMenuOptionColor);
cy.get(jsonFields)
.should('have.css', 'background-color')
.and('include', blackThemeJsonFieldBackColor);
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.and('include', blackThemeSideMenuBackgroundColor);
});
it('should be able to see network parameters - on mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.get(networkParametersNavigation).click();
verifyNetworkParametersPageDisplayed();
cy.get_network_parameters().then((network_parameters) => {
network_parameters = Object.entries(network_parameters);
network_parameters.forEach((network_parameter) => {
const parameterName = network_parameter[0];
cy.get(tableRows)
.contains(parameterName)
.should('be.visible')
.next()
.should('not.be.empty')
.and('be.visible');
});
});
});
});
function verifyNetworkParametersPageDisplayed() {
cy.get('[data-testid="network-param-header"]').should(
'have.text',
'Network Parameters'
);
cy.common_verify_json_parameters(18);
cy.common_verify_json_string_values(6);
cy.common_verify_json_int_values(7);
}
});
@@ -1,3 +1,5 @@
import { BigNumber } from 'bignumber.js';
Cypress.Commands.add(
'common_validate_blocks_data_displayed',
function (headerTestId) {
@@ -25,33 +27,6 @@ Cypress.Commands.add('common_switch_to_mobile_and_click_toggle', function () {
cy.get('[data-testid="open-menu"]').click();
});
Cypress.Commands.add('common_verify_json_parameters', function (expectedNum) {
cy.get('.hljs-attr')
.should('have.length.at.least', expectedNum)
.each(($paramName) => {
cy.wrap($paramName).should('not.be.empty');
});
});
Cypress.Commands.add(
'common_verify_json_string_values',
function (expectedNum) {
cy.get('.hljs-string')
.should('have.length.at.least', expectedNum)
.each(($paramValue) => {
cy.wrap($paramValue).should('not.be.empty');
});
}
);
Cypress.Commands.add('common_verify_json_int_values', function (expectedNum) {
cy.get('.hljs-number')
.should('have.length.at.least', expectedNum)
.each(($paramValue) => {
cy.wrap($paramValue).should('not.be.empty');
});
});
Cypress.Commands.add('monitor_clipboard', () => {
cy.window().then((win) => {
return cy.stub(win, 'prompt').returns(win.prompt);
@@ -72,6 +47,33 @@ Cypress.Commands.add(
'convert_string_json_to_js_object',
{ prevSubject: true },
(jsonBlobString) => {
// Note: this is a chaining function
return JSON.parse(jsonBlobString);
}
);
Cypress.Commands.add(
'add_commas_to_number_if_large_enough',
{ prevSubject: true },
(number) => {
// This will turn 10000000.0000 into 10,000,000.000
// Note: this is a chaining function
const beforeDecimal = number.split('.')[0];
const afterDecimal = number.split('.')[1];
const beforeDecimalWithCommas = beforeDecimal
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
const formattedValue = beforeDecimalWithCommas + '.' + afterDecimal;
return formattedValue;
}
);
Cypress.Commands.add('convert_number_to_eighteen_decimal', (number) => {
// this will take a number like this : 700000000000000000000
// and convert it to a number like this: 700.000000000000000000
return BigNumber((number / 1000000000000000000).toString()).toFixed(18);
});
Cypress.Commands.add('convert_number_to_four_decimal', (number) => {
return parseFloat(number).toFixed(4);
});
+1
View File
@@ -6,6 +6,7 @@ NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https:
NX_VEGA_ENV=STAGNET3
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_BLOCK_EXPLORER=
# App flags
NX_EXPLORER_ASSETS=1
+1
View File
@@ -7,3 +7,4 @@ NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
NX_VEGA_ENV=DEVNET
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_BLOCK_EXPLORER=
+1
View File
@@ -7,3 +7,4 @@ NX_VEGA_URL=https://api.vega.xyz/query
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
NX_VEGA_ENV=MAINNET
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_BLOCK_EXPLORER=
+1
View File
@@ -7,3 +7,4 @@ NX_VEGA_URL=https://api.n01.stagnet3.vega.xyz/graphql
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
NX_VEGA_ENV=STAGNET3
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_BLOCK_EXPLORER=
+1
View File
@@ -1,6 +1,7 @@
# App configuration variables
NX_CHAIN_EXPLORER_URL=https://explorer.vega.trading/.netlify/functions/chain-explorer-api
NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz
NX_BLOCK_EXPLORER=https://n13.testnet.vega.xyz/rest
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n07.testnet.vega.xyz/websocket
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json
NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
+1
View File
@@ -5,3 +5,4 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket
NX_VEGA_URL=http://localhost:3003/query
NX_VEGA_ENV=CUSTOM
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_BLOCK_EXPLORER=
@@ -1,92 +1,90 @@
import { TxsInfiniteListItem } from './txs-infinite-list-item';
import { render, screen, fireEvent, act } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
describe('Txs infinite list item', () => {
it('should display "missing vital data" if "Type" data missing', () => {
it('should display "missing vital data" if "type" data missing', () => {
render(
<TxsInfiniteListItem
// @ts-ignore testing deliberate failure
Type={undefined}
Command={'test'}
Sig={'test'}
PubKey={'test'}
Nonce={1}
TxHash={'test'}
type={undefined}
submitter="test"
hash=""
index={0}
block="1"
/>
);
expect(screen.getByText('Missing vital data')).toBeInTheDocument();
});
it('should display "missing vital data" if "Command" data missing', () => {
it('should display "missing vital data" if "hash" data missing', () => {
render(
<TxsInfiniteListItem
Type={'test'}
// @ts-ignore testing deliberate failure
Command={undefined}
Sig={'test'}
PubKey={'test'}
Nonce={1}
TxHash={'test'}
type="test"
submitter="test"
hash={undefined}
index={0}
block="1"
/>
);
expect(screen.getByText('Missing vital data')).toBeInTheDocument();
});
it('should display "missing vital data" if "Pubkey" data missing', () => {
it('should display "missing vital data" if "submitter" data missing', () => {
render(
<TxsInfiniteListItem
Type={'test'}
Command={'test'}
Sig={'test'}
// @ts-ignore testing deliberate failure
PubKey={undefined}
Nonce={1}
TxHash={'test'}
type="test"
submitter={undefined}
hash="test"
index={0}
block="1"
/>
);
expect(screen.getByText('Missing vital data')).toBeInTheDocument();
});
it('should display "missing vital data" if "TxHash" data missing', () => {
it('should display "missing vital data" if "block" data missing', () => {
render(
<TxsInfiniteListItem
Type={'test'}
Command={'test'}
Sig={'test'}
PubKey={'test'}
Nonce={1}
// @ts-ignore testing deliberate failure
TxHash={undefined}
type="test"
submitter="test"
hash="test"
index={0}
block={undefined}
/>
);
expect(screen.getByText('Missing vital data')).toBeInTheDocument();
});
it('should display "missing vital data" if "index" data missing', () => {
render(
<TxsInfiniteListItem
type="test"
submitter="test"
hash="test"
index={undefined}
block="1"
/>
);
expect(screen.getByText('Missing vital data')).toBeInTheDocument();
});
it('renders data correctly', () => {
const testCommandData = JSON.stringify({
test: 'test of command data',
});
render(
<MemoryRouter>
<TxsInfiniteListItem
Type={'testType'}
Command={testCommandData}
Sig={'testSig'}
PubKey={'testPubKey'}
Nonce={1}
TxHash={'testTxHash'}
type="testType"
submitter="testPubKey"
hash="testTxHash"
index={1}
block="1"
/>
</MemoryRouter>
);
expect(screen.getByTestId('tx-hash')).toHaveTextContent('testTxHash');
expect(screen.getByTestId('pub-key')).toHaveTextContent('testPubKey');
expect(screen.getByTestId('type')).toHaveTextContent('testType');
const button = screen.getByTestId('command-details');
act(() => {
fireEvent.click(button);
});
expect(screen.getByText('"test of command data"')).toBeInTheDocument();
expect(screen.getByTestId('tx-type')).toHaveTextContent('testType');
expect(screen.getByTestId('tx-block')).toHaveTextContent(
'Block 1 (index 1)'
);
});
});
@@ -1,69 +1,60 @@
import React, { useState } from 'react';
import {
Dialog,
Icon,
Intent,
SyntaxHighlighter,
} from '@vegaprotocol/ui-toolkit';
import React from 'react';
import { TruncatedLink } from '../truncate/truncated-link';
import { Routes } from '../../routes/route-names';
import { TxOrderType } from './tx-order-type';
import type { ChainExplorerTxResponse } from '../../routes/types/chain-explorer-response';
import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response';
import { toHex } from '../search/detect-search';
const TRUNCATE_LENGTH = 14;
export const TxsInfiniteListItem = ({
TxHash,
PubKey,
Type,
Command,
}: ChainExplorerTxResponse) => {
const [open, setOpen] = useState(false);
if (!TxHash || !PubKey || !Type || !Command) {
hash,
submitter,
type,
block,
index,
}: Partial<BlockExplorerTransaction>) => {
if (
!hash ||
!submitter ||
!type ||
block === undefined ||
index === undefined
) {
return <div>Missing vital data</div>;
}
return (
<div
data-testid="transaction-row"
className="grid grid-cols-[repeat(2,_1fr)_240px] gap-12 w-full border-t border-neutral-600 dark:border-neutral-800 py-8 txs-infinite-list-item"
className="grid grid-flow-col auto-cols-auto border-t border-neutral-600 dark:border-neutral-800 py-2 txs-infinite-list-item"
>
<div className="whitespace-nowrap overflow-scroll" data-testid="tx-hash">
<div className="whitespace-nowrap" data-testid="tx-type">
<TxOrderType orderType={type} />
</div>
<div className="whitespace-nowrap" data-testid="pub-key">
<TruncatedLink
to={`/${Routes.TX}/${TxHash}`}
text={TxHash}
to={`/${Routes.PARTIES}/${submitter}`}
text={submitter}
startChars={TRUNCATE_LENGTH}
endChars={TRUNCATE_LENGTH}
/>
</div>
<div className="whitespace-nowrap overflow-scroll" data-testid="pub-key">
<div className="whitespace-nowrap" data-testid="tx-hash">
<TruncatedLink
to={`/${Routes.PARTIES}/${PubKey}`}
text={PubKey}
to={`/${Routes.TX}/${toHex(hash)}`}
text={hash}
startChars={TRUNCATE_LENGTH}
endChars={TRUNCATE_LENGTH}
/>
</div>
<div
className="flex justify-between whitespace-nowrap overflow-scroll"
data-testid="type"
>
<TxOrderType orderType={Type} />
<button
title="More details"
onClick={() => setOpen(true)}
data-testid="command-details"
>
<Icon name="search-template" />
</button>
<Dialog
open={open}
onChange={(isOpen) => setOpen(false)}
intent={Intent.None}
>
<SyntaxHighlighter data={JSON.parse(Command)} />
</Dialog>
<div className="whitespace-nowrap" data-testid="tx-block">
<TruncatedLink
to={`/${Routes.BLOCKS}/${block}`}
text={`Block ${block} (index ${index})`}
startChars={TRUNCATE_LENGTH}
endChars={TRUNCATE_LENGTH}
/>
</div>
</div>
);
@@ -1,18 +1,34 @@
import { TxsInfiniteList } from './txs-infinite-list';
import { render, screen, fireEvent, act } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response';
const generateTxs = (number: number) => {
const generateTxs = (number: number): BlockExplorerTransaction[] => {
return Array.from(Array(number)).map((_) => ({
Type: 'ChainEvent',
Command:
'{"txId":"0xc8941ac4ea989988cb8f72e8fdab2e2009376fd17619491439d36b519d27bc93","nonce":"1494","stakingEvent":{"index":"263","block":"14805346","stakeDeposited":{"ethereumAddress":"0x2e5fe63e5d49c26998cf4bfa9b64de1cf9ae7ef2","vegaPublicKey":"657c2a8a5867c43c831e24820b7544e2fdcc1cf610cfe0ece940fe78137400fd","amount":"38471116086510047870875","blockTime":"1652968806"}}}',
Sig: 'fe7624ab742c492cf1e667e79de4777992aca8e093c8707e1f22685c3125c6082cd21b85cd966a61ad4ca0cca2f8bed3082565caa5915bc3b2f78c1ae35cac0b',
PubKey:
'0x7d69327393cdfaaae50e5e215feca65273eafabfb38f32b8124e66298af346d5',
Nonce: 18296387398179254000,
TxHash:
'0x9C753FA6325F7A40D9C4FA5C25E24476C54613E12B1FA2DD841E3BB00D088B77',
block: '87901',
index: 2,
hash: '0F8B98DA0923A50786B852D9CA11E051CACC4C733E1DB93D535C7D81DBD10F6F',
submitter:
'4b782482f587d291e8614219eb9a5ee9280fa2c58982dee71d976782a9be1964',
type: 'Submit Order',
code: 0,
cursor: '87901.2',
command: {
nonce: '4214037379192575529',
blockHeight: '87898',
orderSubmission: {
marketId:
'b4d0a070f5cc73a7d53b23d6f63f8cb52e937ed65d2469a3af4cc1e80e155fcf',
price: '14525946',
size: '54',
side: 'SIDE_SELL',
timeInForce: 'TIME_IN_FORCE_GTT',
expiresAt: '1664966445481288736',
type: 'TYPE_LIMIT',
reference: 'traderbot',
peggedOrder: null,
},
},
}));
};
@@ -41,7 +57,9 @@ describe('Txs infinite list', () => {
error={Error('test error!')}
/>
);
expect(screen.getByText('Error: test error!')).toBeInTheDocument();
expect(
screen.getByText('Cannot fetch transaction: Error: test error!')
).toBeInTheDocument();
});
it('item renders data of n length into list of n length', () => {
@@ -3,19 +3,19 @@ import { FixedSizeList as List } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader';
import { t } from '@vegaprotocol/react-helpers';
import { TxsInfiniteListItem } from './txs-infinite-list-item';
import type { ChainExplorerTxResponse } from '../../routes/types/chain-explorer-response';
import type { BlockExplorerTransaction } from '../../routes/types/block-explorer-response';
interface TxsInfiniteListProps {
hasMoreTxs: boolean;
areTxsLoading: boolean | undefined;
txs: ChainExplorerTxResponse[] | undefined;
txs: BlockExplorerTransaction[] | undefined;
loadMoreTxs: () => void;
error: Error | undefined;
className?: string;
}
interface ItemProps {
index: ChainExplorerTxResponse;
index: BlockExplorerTransaction;
style: React.CSSProperties;
isLoading: boolean;
error: Error | undefined;
@@ -27,19 +27,19 @@ const NOOP = () => {};
const Item = ({ index, style, isLoading, error }: ItemProps) => {
let content;
if (error) {
content = t(`${error}`);
content = t(`Cannot fetch transaction: ${error}`);
} else if (isLoading) {
content = t('Loading...');
} else {
const { TxHash, PubKey, Type, Command, Sig, Nonce } = index;
const { hash, submitter, type, command, block, index: blockIndex } = index;
content = (
<TxsInfiniteListItem
Type={Type}
Command={Command}
Sig={Sig}
PubKey={PubKey}
Nonce={Nonce}
TxHash={TxHash}
type={type}
command={command}
submitter={submitter}
hash={hash}
block={block}
index={blockIndex}
/>
);
}
@@ -71,10 +71,11 @@ export const TxsInfiniteList = ({
return (
<div className={className} data-testid="transactions-list">
<div className="grid grid-cols-[repeat(2,_1fr)_240px] gap-12 w-full mb-8">
<div className="text-lg font-bold">Txn hash</div>
<div className="text-lg font-bold">Party</div>
<div className="grid grid-flow-col auto-cols-auto w-full mb-8">
<div className="text-lg font-bold pl-2">Type</div>
<div className="text-lg font-bold">Submitted By</div>
<div className="text-lg font-bold">Transaction ID</div>
<div className="text-lg font-bold">Block</div>
</div>
<div data-testid="infinite-scroll-wrapper">
<InfiniteLoader
+1
View File
@@ -13,6 +13,7 @@ export const ENV = {
dsn: windowOrDefault('NX_EXPLORER_SENTRY_DSN'),
dataSources: {
chainExplorerUrl: windowOrDefault('NX_CHAIN_EXPLORER_URL'),
blockExplorerUrl: windowOrDefault('NX_BLOCK_EXPLORER'),
tendermintUrl: windowOrDefault('NX_TENDERMINT_URL'),
tendermintWebsocketUrl: windowOrDefault('NX_TENDERMINT_WEBSOCKET_URL'),
},
@@ -1,10 +1,13 @@
import { gql, useQuery } from '@apollo/client';
import { getAssets, t } from '@vegaprotocol/react-helpers';
import { t } from '@vegaprotocol/react-helpers';
import React from 'react';
import { RouteTitle } from '../../components/route-title';
import { SubHeading } from '../../components/sub-heading';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import type { AssetsQuery } from './__generated__/AssetsQuery';
import type {
AssetsQuery,
AssetsQuery_assetsConnection_edges_node,
} from './__generated__/AssetsQuery';
export const ASSETS_QUERY = gql`
query AssetsQuery {
@@ -39,7 +42,10 @@ export const ASSETS_QUERY = gql`
const Assets = () => {
const { data } = useQuery<AssetsQuery>(ASSETS_QUERY);
const assets = getAssets(data);
const assets =
data?.assetsConnection?.edges
?.filter((e) => e && e?.node)
.map((e) => e?.node as AssetsQuery_assetsConnection_edges_node) || [];
return (
<section>
@@ -13,7 +13,7 @@ import Genesis from './genesis';
import { Block } from './blocks/id';
import { Blocks } from './blocks/home';
import { Tx } from './txs/id';
import { TxsHome, TxsHomeFallback } from './txs/home';
import { TxsList } from './txs/home';
import { PendingTxs } from './pending';
import flags from '../config/flags';
import { t } from '@vegaprotocol/react-helpers';
@@ -141,7 +141,7 @@ const routerConfig = [
},
{
index: true,
element: flags.txsList ? <TxsHome /> : <TxsHomeFallback />,
element: <TxsList />,
},
],
},
+42 -91
View File
@@ -1,86 +1,73 @@
import { DATA_SOURCES } from '../../../config';
import { useCallback, useState, useMemo } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { t, useFetch } from '@vegaprotocol/react-helpers';
import { RouteTitle } from '../../../components/route-title';
import { BlocksRefetch } from '../../../components/blocks';
import { JumpToBlock } from '../../../components/jump-to-block';
import { TxsInfiniteList } from '../../../components/txs';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import type { ChainExplorerTxResponse } from '../../types/chain-explorer-response';
import type { TendermintBlockchainResponse } from '../../blocks/tendermint-blockchain-response';
interface TxsProps {
latestBlockHeight: string;
}
import type {
BlockExplorerTransaction,
BlockExplorerTransactions,
} from '../../../routes/types/block-explorer-response';
interface TxsStateProps {
txsData: ChainExplorerTxResponse[];
txsData: BlockExplorerTransaction[];
hasMoreTxs: boolean;
nextPage: number;
lastCursor: string;
}
const Txs = ({ latestBlockHeight }: TxsProps) => {
const [{ txsData, hasMoreTxs, nextPage }, setTxsState] =
const BE_TXS_PER_REQUEST = 100;
export const TxsList = () => {
const [{ txsData, hasMoreTxs, lastCursor }, setTxsState] =
useState<TxsStateProps>({
txsData: [],
hasMoreTxs: true,
nextPage: 1,
lastCursor: '',
});
const reusedBodyParams = useMemo(
() => ({
node_url: DATA_SOURCES.tendermintUrl,
transaction_height: parseInt(latestBlockHeight),
page_size: 30,
}),
[latestBlockHeight]
);
const {
state: { error, loading },
state: { data, error, loading },
refetch,
} = useFetch(
DATA_SOURCES.chainExplorerUrl,
{
method: 'POST',
body: JSON.stringify(reusedBodyParams),
},
} = useFetch<BlockExplorerTransactions>(
`${DATA_SOURCES.blockExplorerUrl}/transactions?` +
new URLSearchParams({
limit: BE_TXS_PER_REQUEST.toString(10),
}),
{},
false
);
const loadTxs = useCallback(async () => {
const data = await refetch(
undefined,
JSON.stringify({
...reusedBodyParams,
page_number: nextPage,
})
);
if (data) {
useEffect(() => {
if (data?.transactions?.length) {
setTxsState((prev) => ({
...prev,
nextPage: prev.nextPage + 1,
txsData: [...prev.txsData, ...data.transactions],
hasMoreTxs: true,
txsData: [...prev.txsData, ...(data as ChainExplorerTxResponse[])],
lastCursor:
data.transactions[data.transactions.length - 1].cursor || '',
}));
}
}, [nextPage, refetch, reusedBodyParams]);
}, [data?.transactions]);
const loadTxs = useCallback(() => {
return refetch({
limit: BE_TXS_PER_REQUEST,
before: lastCursor,
});
}, [lastCursor, refetch]);
const refreshTxs = useCallback(async () => {
setTxsState((prev) => ({
...prev,
lastCursor: '',
hasMoreTxs: true,
txsData: [],
}));
}, [setTxsState]);
return (
<section>
<RouteTitle>{t('Transactions')}</RouteTitle>
<BlocksRefetch
refetch={() =>
refetch(
undefined,
JSON.stringify({
...reusedBodyParams,
page_number: 1,
})
)
}
/>
<BlocksRefetch refetch={refreshTxs} />
<TxsInfiniteList
hasMoreTxs={hasMoreTxs}
areTxsLoading={loading}
@@ -89,42 +76,6 @@ const Txs = ({ latestBlockHeight }: TxsProps) => {
error={error}
className="mb-28"
/>
<JumpToBlock />
</section>
);
};
export const TxsHome = () => {
const {
state: { data, error, loading },
} = useFetch<TendermintBlockchainResponse>(
`${DATA_SOURCES.tendermintUrl}/blockchain`
);
return (
<AsyncRenderer
loading={!!loading}
loadingMessage={t('Getting latest block height...')}
error={error}
data={data}
noDataMessage={t('Could not get latest block height')}
render={(data) => (
<Txs
latestBlockHeight={
data?.result?.block_metas?.[0]?.header?.height || ''
}
/>
)}
/>
);
};
export const TxsHomeFallback = () => (
<>
<RouteTitle>{t('Transactions')}</RouteTitle>
<div>
The transactions list is currently disabled. Please use the search bar to
discover transaction data
</div>
</>
);
@@ -0,0 +1,14 @@
export interface BlockExplorerTransaction {
block: string;
index: number;
hash: string;
submitter: string;
type: string;
code: number;
cursor: string;
command: Record<string, unknown>;
}
export interface BlockExplorerTransactions {
transactions: BlockExplorerTransaction[];
}
+288 -54
View File
@@ -232,7 +232,7 @@
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "129999.45",
"total_removed": "0",
"locked_amount": "101055.803023481857846155",
"locked_amount": "99808.964557038223180575",
"deposits": [
{
"amount": "129999.45",
@@ -298,7 +298,7 @@
"tranche_end": "2023-09-03T00:00:00.000Z",
"total_added": "52600",
"total_removed": "0",
"locked_amount": "47987.1788178589567",
"locked_amount": "47229.74949264333032",
"deposits": [
{
"amount": "2600",
@@ -471,7 +471,7 @@
"tranche_end": "2023-09-17T00:00:00.000Z",
"total_added": "5000",
"total_removed": "0",
"locked_amount": "4753.299720953831",
"locked_amount": "4681.3007356671745",
"deposits": [
{
"amount": "5000",
@@ -682,7 +682,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "97499.58",
"total_removed": "0",
"locked_amount": "42348.530615082211097964",
"locked_amount": "41125.4982277578856557894",
"deposits": [
{
"amount": "97499.58",
@@ -715,7 +715,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "135173.4239508",
"total_removed": "0",
"locked_amount": "57883.13018201161087005483132",
"locked_amount": "56211.456056272351055479479",
"deposits": [
{
"amount": "135173.4239508",
@@ -748,7 +748,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "32499.86",
"total_removed": "0",
"locked_amount": "17815.295509758479255574",
"locked_amount": "17300.786905050761868906",
"deposits": [
{
"amount": "32499.86",
@@ -781,7 +781,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "10833.29",
"total_removed": "0",
"locked_amount": "5798.705812890794772696",
"locked_amount": "5631.238254731752483847",
"deposits": [
{
"amount": "10833.29",
@@ -814,7 +814,7 @@
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "22749.93",
"total_removed": "0",
"locked_amount": "21676.857446138743511523",
"locked_amount": "21050.826310536649083198",
"deposits": [
{
"amount": "6500",
@@ -889,7 +889,7 @@
"tranche_end": "2022-11-01T00:00:00.000Z",
"total_added": "30000",
"total_removed": "0",
"locked_amount": "4400.6868961352664",
"locked_amount": "3543.74245169082",
"deposits": [
{
"amount": "7500",
@@ -1006,7 +1006,7 @@
"tranche_end": "2023-06-02T00:00:00.000Z",
"total_added": "1939928.38",
"total_removed": "626880.6921411330574",
"locked_amount": "1275520.872149814893848934",
"locked_amount": "1247586.29717205741791664",
"deposits": [
{
"amount": "1852091.69",
@@ -1303,7 +1303,7 @@
"tranche_end": "2023-02-01T00:00:00.000Z",
"total_added": "42500",
"total_removed": "0",
"locked_amount": "27484.30643619162825",
"locked_amount": "26270.30180656199925",
"deposits": [
{
"amount": "12500",
@@ -2181,7 +2181,7 @@
"tranche_start": "2021-09-05T00:00:00.000Z",
"tranche_end": "2022-09-30T00:00:00.000Z",
"total_added": "60916.66666633337",
"total_removed": "22679.59090768217556896",
"total_removed": "22920.80703869967556896",
"locked_amount": "0",
"deposits": [
{
@@ -2281,6 +2281,11 @@
}
],
"withdrawals": [
{
"amount": "241.2161310175",
"user": "0x1887D97F9C875108Aa6bE109B282f87A666472f2",
"tx": "0xeb4604db9ecd236bfe8a3481989577fd57b942e9900342c23497dedfdf85a0ef"
},
{
"amount": "1983.33333333333",
"user": "0xED5847639328EDd38E7CE934442FF4eE8e714f7C",
@@ -2989,6 +2994,12 @@
}
],
"withdrawals": [
{
"amount": "241.2161310175",
"user": "0x1887D97F9C875108Aa6bE109B282f87A666472f2",
"tranche_id": 13,
"tx": "0xeb4604db9ecd236bfe8a3481989577fd57b942e9900342c23497dedfdf85a0ef"
},
{
"amount": "339.9854953025",
"user": "0x1887D97F9C875108Aa6bE109B282f87A666472f2",
@@ -3075,8 +3086,8 @@
}
],
"total_tokens": "4250",
"withdrawn_tokens": "4008.7838689825",
"remaining_tokens": "241.2161310175"
"withdrawn_tokens": "4250",
"remaining_tokens": "0"
},
{
"address": "0x9fd50776F133751E8Ae6abE1Be124638Bb917E05",
@@ -5940,7 +5951,7 @@
"tranche_start": "2021-09-03T00:00:00.000Z",
"tranche_end": "2022-09-03T00:00:00.000Z",
"total_added": "39600.000000000000000003",
"total_removed": "23868.97808024224",
"total_removed": "23872.84141180056",
"locked_amount": "0",
"deposits": [
{
@@ -12560,6 +12571,11 @@
}
],
"withdrawals": [
{
"amount": "3.86333155832",
"user": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2",
"tx": "0x068081c78445c62a22f68a81cbfd73d1c906b35c31882e5dcbd95b158485b227"
},
{
"amount": "505",
"user": "0x2f28F3Be9315cD7F2475F6500020262bd8505fA1",
@@ -19110,6 +19126,12 @@
}
],
"withdrawals": [
{
"amount": "3.86333155832",
"user": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2",
"tranche_id": 11,
"tx": "0x068081c78445c62a22f68a81cbfd73d1c906b35c31882e5dcbd95b158485b227"
},
{
"amount": "41.64068004762",
"user": "0xC6D7208DaDEe4F431bd0f3f11E7d4c91fF51bfb2",
@@ -19124,8 +19146,8 @@
}
],
"total_tokens": "104",
"withdrawn_tokens": "100.13666844168",
"remaining_tokens": "3.86333155832"
"withdrawn_tokens": "104",
"remaining_tokens": "0"
},
{
"address": "0xd996efF75E43357F04E3f37D61EF6A6851A0b8f1",
@@ -24352,8 +24374,8 @@
"tranche_start": "2022-03-05T00:00:00.000Z",
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "3732368.4671",
"total_removed": "212048.9552173080602",
"locked_amount": "1984532.81602302279885050992",
"total_removed": "216488.8190253099792",
"locked_amount": "1941607.10006823176798276368",
"deposits": [
{
"amount": "1998.95815",
@@ -24522,6 +24544,11 @@
}
],
"withdrawals": [
{
"amount": "4439.863808001919",
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
"tx": "0x0036b66c9129b9c96b3e456e7958216ed7a9d4e9f2ad548bb8b4e8a036bd70d6"
},
{
"amount": "3087.2670009465625",
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
@@ -24696,6 +24723,12 @@
}
],
"withdrawals": [
{
"amount": "4439.863808001919",
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
"tranche_id": 1,
"tx": "0x0036b66c9129b9c96b3e456e7958216ed7a9d4e9f2ad548bb8b4e8a036bd70d6"
},
{
"amount": "3087.2670009465625",
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
@@ -24782,8 +24815,8 @@
}
],
"total_tokens": "187637.95",
"withdrawn_tokens": "84806.4863872416465",
"remaining_tokens": "102831.4636127583535"
"withdrawn_tokens": "89246.3501952435655",
"remaining_tokens": "98391.5998047564345"
},
{
"address": "0x1A71e3ED1996CAbB91bB043f880CE963D601707e",
@@ -25264,8 +25297,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-12-05T00:00:00.000Z",
"total_added": "15870102.715470999700000001",
"total_removed": "222408.2894258465985744",
"locked_amount": "12336713.5320731118005870614596262497620979",
"total_removed": "224997.4571492768169494",
"locked_amount": "12184501.6993918133532141480489084640578535",
"deposits": [
{
"amount": "16249.93",
@@ -25769,6 +25802,21 @@
}
],
"withdrawals": [
{
"amount": "243.932422174205",
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
"tx": "0x9962e848bcc9ec1ee7db91bafe00948c766bf7184d20f39bfe08539928844213"
},
{
"amount": "981.32183505687375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xdc3bc277d041e6dff7fb11e0be0a500fadda69ab829b0c6d5caa196031062f40"
},
{
"amount": "432.7384147709755",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0xa3998f6f73372f3841256fc23cb4e182545252515cd8d25d5d228d13636b435c"
},
{
"amount": "668.448073601292875",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -25839,6 +25887,16 @@
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x9cf6b1e7e12f0786a9aff09f0379ba8162ea88a8357a8e28c562b618093d0f5f"
},
{
"amount": "501.731430959210375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x1e91d12aef9afe631095ded8bd5ff6e0a40e5aa87271f46078b3175f41f4ee39"
},
{
"amount": "429.44362046895375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tx": "0x10f121ed91c0f605893d86d1eed2ccca505b86c73c89c30e0dfb90edcff637b0"
},
{
"amount": "504.652814859004625",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -26512,6 +26570,18 @@
}
],
"withdrawals": [
{
"amount": "981.32183505687375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0xdc3bc277d041e6dff7fb11e0be0a500fadda69ab829b0c6d5caa196031062f40"
},
{
"amount": "432.7384147709755",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0xa3998f6f73372f3841256fc23cb4e182545252515cd8d25d5d228d13636b435c"
},
{
"amount": "668.448073601292875",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -26572,6 +26642,18 @@
"tranche_id": 2,
"tx": "0x9cf6b1e7e12f0786a9aff09f0379ba8162ea88a8357a8e28c562b618093d0f5f"
},
{
"amount": "501.731430959210375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0x1e91d12aef9afe631095ded8bd5ff6e0a40e5aa87271f46078b3175f41f4ee39"
},
{
"amount": "429.44362046895375",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
"tranche_id": 2,
"tx": "0x10f121ed91c0f605893d86d1eed2ccca505b86c73c89c30e0dfb90edcff637b0"
},
{
"amount": "504.652814859004625",
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
@@ -27150,8 +27232,8 @@
}
],
"total_tokens": "259998.8875",
"withdrawn_tokens": "57731.002552864795",
"remaining_tokens": "202267.884947135205"
"withdrawn_tokens": "60076.237854120808375",
"remaining_tokens": "199922.649645879191625"
},
{
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
@@ -28045,6 +28127,12 @@
}
],
"withdrawals": [
{
"amount": "243.932422174205",
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
"tranche_id": 2,
"tx": "0x9962e848bcc9ec1ee7db91bafe00948c766bf7184d20f39bfe08539928844213"
},
{
"amount": "169.6116120463555",
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
@@ -28119,8 +28207,8 @@
}
],
"total_tokens": "12362.05",
"withdrawn_tokens": "2584.0836409459565",
"remaining_tokens": "9777.9663590540435"
"withdrawn_tokens": "2828.0160631201615",
"remaining_tokens": "9534.0339368798385"
},
{
"address": "0xb091D456d0dFCB94dcba6f355379056C5bb995fC",
@@ -28744,8 +28832,8 @@
"tranche_start": "2021-11-05T00:00:00.000Z",
"tranche_end": "2023-05-05T00:00:00.000Z",
"total_added": "14597706.0446472999",
"total_removed": "2923085.955595204497185312",
"locked_amount": "5667729.935859967841691532439599905",
"total_removed": "2926333.340895590665080812",
"locked_amount": "5527208.943810320731141048979540034",
"deposits": [
{
"amount": "129284.449",
@@ -28954,6 +29042,16 @@
}
],
"withdrawals": [
{
"amount": "1360.2331260920135955",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x8c5fe9e7c9b1ff5e11cd044869b4d43b06512d8a8037c945315e44b2829b49d8"
},
{
"amount": "598.630467392367358",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0xfccb647f645ad7c56c3f73a6b92b19dcad5100cf5dbbaf8a885793d353053f08"
},
{
"amount": "927.5894688774561055",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -29024,6 +29122,16 @@
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0xb45a95262772c307dd2f75b2cba4d5e7d12968b5a04a7ca6c59f5c99ab54815a"
},
{
"amount": "690.53070553304891625",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x16096cd1bc7539778177c7db0fcda97d0085a63b13ebd3a751648337b698d8aa"
},
{
"amount": "597.99100136873802575",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tx": "0x6fdfd3c077574cd9b9ede40db9488759ceac7d430e6ad09fdbd5a64bd87ce8b3"
},
{
"amount": "700.967684681521309",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -31195,6 +31303,18 @@
}
],
"withdrawals": [
{
"amount": "1360.2331260920135955",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0x8c5fe9e7c9b1ff5e11cd044869b4d43b06512d8a8037c945315e44b2829b49d8"
},
{
"amount": "598.630467392367358",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0xfccb647f645ad7c56c3f73a6b92b19dcad5100cf5dbbaf8a885793d353053f08"
},
{
"amount": "927.5894688774561055",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -31255,6 +31375,18 @@
"tranche_id": 3,
"tx": "0xb45a95262772c307dd2f75b2cba4d5e7d12968b5a04a7ca6c59f5c99ab54815a"
},
{
"amount": "690.53070553304891625",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0x16096cd1bc7539778177c7db0fcda97d0085a63b13ebd3a751648337b698d8aa"
},
{
"amount": "597.99100136873802575",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
"tranche_id": 3,
"tx": "0x6fdfd3c077574cd9b9ede40db9488759ceac7d430e6ad09fdbd5a64bd87ce8b3"
},
{
"amount": "700.967684681521309",
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
@@ -33111,8 +33243,8 @@
}
],
"total_tokens": "359123.469575",
"withdrawn_tokens": "219475.84527111689429425",
"remaining_tokens": "139647.62430388310570575"
"withdrawn_tokens": "222723.23057150306218975",
"remaining_tokens": "136400.23900349693781025"
},
{
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
@@ -34223,8 +34355,8 @@
"tranche_start": "2021-10-05T00:00:00.000Z",
"tranche_end": "2023-04-05T00:00:00.000Z",
"total_added": "5778205.3912159303",
"total_removed": "1859061.122194459692887301",
"locked_amount": "1922450.97226335538560662121602032",
"total_removed": "1873909.449655528970703801",
"locked_amount": "1866930.278440655586530334992507438",
"deposits": [
{
"amount": "552496.6455",
@@ -34368,6 +34500,16 @@
}
],
"withdrawals": [
{
"amount": "14848.19419062596735675",
"user": "0x9058e12e2F32cB1cD4D3123359963D77786477FC",
"tx": "0x51d2a4b9c2db0dc6c34ee296e468d44d074a1debd4271d66cb1eeb1cc449860f"
},
{
"amount": "0.13327044331045975",
"user": "0x9058e12e2F32cB1cD4D3123359963D77786477FC",
"tx": "0x31bcddc1d9f267c2337fba36d44e2282388183e2608a7781fedeaa7abb002482"
},
{
"amount": "4240.023826533383217",
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
@@ -35030,6 +35172,18 @@
}
],
"withdrawals": [
{
"amount": "14848.19419062596735675",
"user": "0x9058e12e2F32cB1cD4D3123359963D77786477FC",
"tranche_id": 4,
"tx": "0x51d2a4b9c2db0dc6c34ee296e468d44d074a1debd4271d66cb1eeb1cc449860f"
},
{
"amount": "0.13327044331045975",
"user": "0x9058e12e2F32cB1cD4D3123359963D77786477FC",
"tranche_id": 4,
"tx": "0x31bcddc1d9f267c2337fba36d44e2282388183e2608a7781fedeaa7abb002482"
},
{
"amount": "2155.49461457390087475",
"user": "0x9058e12e2F32cB1cD4D3123359963D77786477FC",
@@ -35044,8 +35198,8 @@
}
],
"total_tokens": "27624.882275",
"withdrawn_tokens": "3835.43954817344395075",
"remaining_tokens": "23789.44272682655604925"
"withdrawn_tokens": "18683.76700924272176725",
"remaining_tokens": "8941.11526575727823275"
},
{
"address": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75",
@@ -35753,8 +35907,8 @@
"tranche_start": "2022-06-05T00:00:00.000Z",
"tranche_end": "2023-06-05T00:00:00.000Z",
"total_added": "472355.6199999996",
"total_removed": "4160.13945227826",
"locked_amount": "314460.5687720519725132450634196",
"total_removed": "4675.66485244886",
"locked_amount": "307658.74370516207651625788635212",
"deposits": [
{
"amount": "3000",
@@ -42373,6 +42527,16 @@
}
],
"withdrawals": [
{
"amount": "95.248756976",
"user": "0xA17b91BdDcE741528fDDF8E5738A767B3053ac18",
"tx": "0xad37bdd4cbd855be571f4fd5157688a34b1e9f9f90f93f9460e5123ca221a319"
},
{
"amount": "48.7169590306",
"user": "0xB168ce7397Dc52ed13B4eD8119f309ec30DDa2c9",
"tx": "0xdca459e274a6629dbb7e9a0874f254b1c8970d73e46ceb42432a70e1690e4227"
},
{
"amount": "65.770370368",
"user": "0x7708B79e2bc3b7ab816E66aF33A8c9385f0FcA4b",
@@ -42408,6 +42572,31 @@
"user": "0xA0beaa6EC671f4cC8B6D6cA52C46D6c252F525a8",
"tx": "0x026f716e8e3cc425aaa9a78b34a685f788d52a14d843dc2ed2430a400194b1ac"
},
{
"amount": "24.760013952",
"user": "0x4d4AA3f302cbA998AAFC03F9d73484434ed9Fd53",
"tx": "0x6137b5d86d1038fbad53e50bb0d1f76dbd67a4fef4c2bf9176608c4d1e15ebbe"
},
{
"amount": "13.344748856",
"user": "0x4eD2b3c68BB4fda084ce1591a210F4aC8b71234A",
"tx": "0x1ce993074ad983b356da0559cd03cde2632665ec9cddaf20ba384fc325cbde60"
},
{
"amount": "135.474264332",
"user": "0xe28dBf57Ad23cc0c32b6769556CD3c64873b4330",
"tx": "0xc706b9ab1e410b4de90f3969faeec3b7bd71de1c3d1de4eb9ccda0b8be02d1a9"
},
{
"amount": "61.83652968",
"user": "0x7345AaA0D0e4C4A46d921fA9323973956F2b7392",
"tx": "0xc79c54283a3bdd5944f0098641f9537a62c433718a4c391f01684255155ef9d2"
},
{
"amount": "136.144127344",
"user": "0xb1EAD214506D0cD73785Dd09B3EfC2307133bf69",
"tx": "0xe563eb4f77cb43e4eeb099bf3d7134e54f2a2d046d77785570afa2869bc0f997"
},
{
"amount": "52.731139014",
"user": "0x28FC83947F02f59Cb36b40f97f2D32BBC5D00585",
@@ -49885,6 +50074,12 @@
}
],
"withdrawals": [
{
"amount": "95.248756976",
"user": "0xA17b91BdDcE741528fDDF8E5738A767B3053ac18",
"tranche_id": 5,
"tx": "0xad37bdd4cbd855be571f4fd5157688a34b1e9f9f90f93f9460e5123ca221a319"
},
{
"amount": "42.526268388",
"user": "0xA17b91BdDcE741528fDDF8E5738A767B3053ac18",
@@ -49893,8 +50088,8 @@
}
],
"total_tokens": "400",
"withdrawn_tokens": "42.526268388",
"remaining_tokens": "357.473731612"
"withdrawn_tokens": "137.775025364",
"remaining_tokens": "262.224974636"
},
{
"address": "0x8CF85d1ecC6eDd70000c57E31ff8FC18633F7328",
@@ -50888,10 +51083,17 @@
"tx": "0x96a22c369645e8945b4047374a05332f4054b50a492c43092e8bb8e974a006b9"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "48.7169590306",
"user": "0xB168ce7397Dc52ed13B4eD8119f309ec30DDa2c9",
"tranche_id": 5,
"tx": "0xdca459e274a6629dbb7e9a0874f254b1c8970d73e46ceb42432a70e1690e4227"
}
],
"total_tokens": "140",
"withdrawn_tokens": "0",
"remaining_tokens": "140"
"withdrawn_tokens": "48.7169590306",
"remaining_tokens": "91.2830409694"
},
{
"address": "0xdD37b0ff9aE7e2EDbABdc291e8d44431084dA4c2",
@@ -54673,6 +54875,12 @@
}
],
"withdrawals": [
{
"amount": "13.344748856",
"user": "0x4eD2b3c68BB4fda084ce1591a210F4aC8b71234A",
"tranche_id": 5,
"tx": "0x1ce993074ad983b356da0559cd03cde2632665ec9cddaf20ba384fc325cbde60"
},
{
"amount": "26.406887368",
"user": "0x4eD2b3c68BB4fda084ce1591a210F4aC8b71234A",
@@ -54705,8 +54913,8 @@
}
],
"total_tokens": "400",
"withdrawn_tokens": "121.366349568",
"remaining_tokens": "278.633650432"
"withdrawn_tokens": "134.711098424",
"remaining_tokens": "265.288901576"
},
{
"address": "0x5c90765F50629570738fEe7b7FA82ae118f81Ed1",
@@ -56226,10 +56434,17 @@
"tx": "0xe32a466fc780a0fb3fd84a804f622931ebfaf3f428bff0dc6d141270410e75f8"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "136.144127344",
"user": "0xb1EAD214506D0cD73785Dd09B3EfC2307133bf69",
"tranche_id": 5,
"tx": "0xe563eb4f77cb43e4eeb099bf3d7134e54f2a2d046d77785570afa2869bc0f997"
}
],
"total_tokens": "400",
"withdrawn_tokens": "0",
"remaining_tokens": "400"
"withdrawn_tokens": "136.144127344",
"remaining_tokens": "263.855872656"
},
{
"address": "0xDcD1000CB62FAE013aEd379d9F1287D828bcEaA3",
@@ -56725,10 +56940,17 @@
"tx": "0xb1425d9b0d5f10c5b06236d6f9d61ebddd21c4027e0f41deb5ec227a1753c715"
}
],
"withdrawals": [],
"withdrawals": [
{
"amount": "135.474264332",
"user": "0xe28dBf57Ad23cc0c32b6769556CD3c64873b4330",
"tranche_id": 5,
"tx": "0xc706b9ab1e410b4de90f3969faeec3b7bd71de1c3d1de4eb9ccda0b8be02d1a9"
}
],
"total_tokens": "400",
"withdrawn_tokens": "0",
"remaining_tokens": "400"
"withdrawn_tokens": "135.474264332",
"remaining_tokens": "264.525735668"
},
{
"address": "0xff2D0F83b812bfbFe5aafca081140C59f67d5fd3",
@@ -58600,6 +58822,12 @@
}
],
"withdrawals": [
{
"amount": "61.83652968",
"user": "0x7345AaA0D0e4C4A46d921fA9323973956F2b7392",
"tranche_id": 5,
"tx": "0xc79c54283a3bdd5944f0098641f9537a62c433718a4c391f01684255155ef9d2"
},
{
"amount": "201.207077628",
"user": "0x7345AaA0D0e4C4A46d921fA9323973956F2b7392",
@@ -58614,8 +58842,8 @@
}
],
"total_tokens": "1200",
"withdrawn_tokens": "344.995395732",
"remaining_tokens": "855.004604268"
"withdrawn_tokens": "406.831925412",
"remaining_tokens": "793.168074588"
},
{
"address": "0x47181cf36aDFb0b5dB7EfDB123f403D890607841",
@@ -61660,6 +61888,12 @@
}
],
"withdrawals": [
{
"amount": "24.760013952",
"user": "0x4d4AA3f302cbA998AAFC03F9d73484434ed9Fd53",
"tranche_id": 5,
"tx": "0x6137b5d86d1038fbad53e50bb0d1f76dbd67a4fef4c2bf9176608c4d1e15ebbe"
},
{
"amount": "14.663413242",
"user": "0x4d4AA3f302cbA998AAFC03F9d73484434ed9Fd53",
@@ -61674,8 +61908,8 @@
}
],
"total_tokens": "200",
"withdrawn_tokens": "42.270268898",
"remaining_tokens": "157.729731102"
"withdrawn_tokens": "67.03028285",
"remaining_tokens": "132.96971715"
},
{
"address": "0xd9390b46a1749DEe5325A490490491db9a826D1F",
+3
View File
@@ -40,6 +40,9 @@ module.exports = defineConfig({
vegaWalletPublicKey:
'02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65',
vegaWalletPublicKeyShort: '02ecea…2f65',
vegaWalletPublicKey2:
'7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535',
vegaWalletPublicKey2Short: '7f9cf0…5535',
vegaTokenContractAddress: '0xF41bD86d462D36b997C0bbb4D97a0a3382f205B7',
vegaTokenAddress: '0x67175Da1D5e966e40D11c4B2519392B2058373de',
txTimeout: { timeout: 70000 },
@@ -0,0 +1,13 @@
{
"changes": {
"name": "USDT Coin",
"symbol": "USDT",
"decimals": "18",
"quantum": "1",
"erc20": {
"contractAddress": "0xb404c51bbc10dcbe948077f18a4b8e553d160084",
"withdrawThreshold": "10",
"lifetimeLimit": "10"
}
}
}
@@ -0,0 +1,80 @@
{
"changes": {
"decimalPlaces": "5",
"positionDecimalPlaces": "5",
"instrument": {
"name": "Oranges Daily",
"code": "ORANGES.24h",
"future": {
"settlementAsset": "8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4",
"quoteName": "tEuro",
"settlementDataDecimals": 5,
"oracleSpecForSettlementPrice": {
"pubKeys": ["0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"],
"filters": [
{
"key": {
"name": "prices.BTC.value",
"type": "TYPE_INTEGER"
},
"conditions": [
{
"operator": "OPERATOR_GREATER_THAN",
"value": "0"
}
]
}
]
},
"oracleSpecForTradingTermination": {
"pubKeys": ["0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"],
"filters": [
{
"key": {
"name": "vegaprotocol.builtin.timestamp",
"type": "TYPE_TIMESTAMP"
},
"conditions": [
{
"operator": "OPERATOR_GREATER_THAN_OR_EQUAL",
"value": "1648684800000000000"
}
]
}
]
},
"oracleSpecBinding": {
"settlementPriceProperty": "prices.BTC.value",
"tradingTerminationProperty": "vegaprotocol.builtin.timestamp"
}
}
},
"metadata": ["sector:food", "sector:materials", "source:docs.vega.xyz"],
"priceMonitoringParameters": {
"triggers": [
{
"horizon": "43200",
"probability": "0.9999999",
"auctionExtension": "600"
}
]
},
"liquidityMonitoringParameters": {
"targetStakeParameters": {
"timeWindow": "3600",
"scalingFactor": 10
},
"triggeringRatio": 0.7,
"auctionExtension": "1"
},
"logNormal": {
"tau": 0.0001140771161,
"riskAversionParameter": 0.001,
"params": {
"mu": 0,
"r": 0.016,
"sigma": 0.8
}
}
}
}
@@ -1,6 +1,6 @@
{
"rationale": {
"title": "An example freeform proposal with unique number of: ",
"title": "An example raw proposal with unique number of: ",
"description": "I propose that everyone evaluate the following IPFS document and vote Yes if they agree. [bafybeigwwctpv37xdcwacqxvekr6e4kaemqsrv34em6glkbiceo3fcy4si](https://dweb.link/ipfs/bafybeigwwctpv37xdcwacqxvekr6e4kaemqsrv34em6glkbiceo3fcy4si)"
},
"terms": {
@@ -0,0 +1,69 @@
{
"marketId": "315a8e48db0a292c92b617264728048c82c20efc922c75fd292fc54e5c727c81",
"changes": {
"instrument": {
"code": "ORANGES.24h",
"future": {
"quoteName": "tEuro",
"settlementDataDecimals": 5,
"oracleSpecForSettlementPrice": {
"pubKeys": ["0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"],
"filters": [
{
"key": {
"name": "prices.BTC.value",
"type": "TYPE_INTEGER"
},
"conditions": [
{
"operator": "OPERATOR_GREATER_THAN",
"value": "0"
}
]
}
]
},
"oracleSpecForTradingTermination": {
"pubKeys": ["0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"],
"filters": [
{
"key": {
"name": "vegaprotocol.builtin.timestamp",
"type": "TYPE_TIMESTAMP"
},
"conditions": [
{
"operator": "OPERATOR_GREATER_THAN_OR_EQUAL",
"value": "1648684800000000000"
}
]
}
]
},
"oracleSpecBinding": {
"settlementPriceProperty": "prices.BTC.value",
"tradingTerminationProperty": "vegaprotocol.builtin.timestamp"
}
}
},
"metadata": ["sector:energy", "sector:food", "source:docs.vega.xyz"],
"priceMonitoringParameters": {
"triggers": [
{
"horizon": "43200",
"probability": "0.9999999",
"auctionExtension": "600"
}
]
},
"logNormal": {
"tau": 0.0001140771161,
"riskAversionParameter": 0.001,
"params": {
"mu": 0,
"r": 0.016,
"sigma": 0.3
}
}
}
}
@@ -1,5 +1,4 @@
/// <reference types="cypress" />
const vegaWalletUnstakedBalance =
'[data-testid="vega-wallet-balance-unstaked"]';
const vegaWalletStakedBalances =
@@ -28,16 +27,20 @@ const changeVoteButton = '[data-testid="change-vote-button"]';
const proposalDetailsTitle = '[data-testid="proposal-title"]';
const proposalDetailsDescription = '[data-testid="proposal-description"]';
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
const minVoteButton = '[data-testid="min-vote"]';
const maxVoteButton = '[data-testid="max-vote"]';
const voteButtons = '[data-testid="vote-buttons"]';
const votingDate = '[data-testid="voting-date"]';
const voteTwoMinExtraNote = '[data-testid="voting-2-mins-extra"]';
const voteStatus = '[data-testid="vote-status"]';
const rejectProposalsLink = '[href="/governance/rejected"]';
const feedbackError = '[data-testid="Error"]';
const txTimeout = Cypress.env('txTimeout');
const epochTimeout = Cypress.env('epochTimeout');
const proposalTimeout = { timeout: 14000 };
const restConnectorForm = '[data-testid="rest-connector-form"]';
const noOpenProposals = '[data-testid="no-open-proposals"]';
const noClosedProposals = '[data-testid="no-closed-proposals"]';
const txTimeout = Cypress.env('txTimeout');
const epochTimeout = Cypress.env('epochTimeout');
const proposalTimeout = { timeout: 14000 };
const governanceProposalType = {
NETWORK_PARAMETER: 'Network parameter',
@@ -45,6 +48,7 @@ const governanceProposalType = {
UPDATE_MARKET: 'Update market',
NEW_ASSET: 'New asset',
FREEFORM: 'Freeform',
RAW: 'raw proposal',
};
context(
@@ -142,7 +146,7 @@ context(
});
});
it('should be able to see that no proposals exist', function () {
it('Should be able to see that no proposals exist', function () {
// 1004-VOTE-003
cy.get(noOpenProposals)
.should('be.visible')
@@ -152,13 +156,17 @@ context(
.and('have.text', 'There are no enacted or rejected proposals');
});
// 1005-PROP-002
// 1005-PROP-003
it('Submit a proposal form - shows how many vega tokens are required to make a proposal', function () {
// 1005-PROP-005
cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET);
cy.contains(
`You must have at least ${this.minProposerBalance} VEGA associated to make a proposal`
).should('be.visible');
});
// 1005-PROP-011
it(
'Able to submit a valid freeform proposal - with minimum required tokens associated',
{ tags: '@smoke' },
@@ -166,20 +174,19 @@ context(
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.get(minVoteButton).should('be.visible'); // 1005-PROP-008
cy.get(maxVoteButton).should('be.visible');
cy.get(votingDate).should('not.be.empty');
cy.get(voteTwoMinExtraNote).should(
'contain.text',
'we add 2 minutes of extra time'
);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Confirm transaction in wallet', epochTimeout).should(
'be.visible'
);
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should(
'be.visible'
);
cy.get(dialogCloseButton).click();
// 1005-PROP-012
// 1005-PROP-016
cy.wait_for_proposal_submitted();
}
);
@@ -190,8 +197,7 @@ context(
cy.navigate_to_page_if_not_already_loaded('governance');
cy.get(vegaWalletUnstakedBalance, txTimeout).should(
'contain',
this.minProposerBalance,
txTimeout
this.minProposerBalance
);
cy.navigate_to('staking');
cy.wait_for_spinner();
@@ -200,63 +206,19 @@ context(
cy.get(vegaWalletStakedBalances, txTimeout).should(
'contain',
this.minProposerBalance,
txTimeout
);
cy.navigate_to('governance');
cy.wait_for_spinner();
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
});
it('Newly created freeform proposals list - able to filter by proposalID to show it in list', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.navigate_to('governance');
cy.wait_for_spinner();
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
cy.wait('@proposalSubmissionCompletion')
.its(proposalResponseProposalIdPath)
.then((proposalId) => {
cy.get('[data-testid="set-proposals-filter-visible"]').click();
cy.get('[data-testid="filter-input"]').type(proposalId);
cy.get(`#${proposalId}`).should('contain', proposalId);
});
cy.wait_for_proposal_submitted();
});
it('Newly created freeform proposals list - able to filter by proposerID to show it in list', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
it('Newly created proposals list - able to filter by proposerID to show it in list', function () {
createFreeformProposal(this.minProposerBalance);
cy.wait('@proposalSubmissionCompletion').then((proposal) => {
let proposerId = proposal.request.body.variables.partyId;
let proposalId = proposal.response.body.data.busEvents[0].event.id;
@@ -266,36 +228,22 @@ context(
});
});
it('Newly created freeform proposals list - shows title and portion of summary', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50').as('freeformProposal');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
it('Newly created proposals list - shows title and portion of summary', function () {
createRawProposal(this.minProposerBalance);
cy.wait('@proposalSubmissionCompletion')
.its(proposalResponseProposalIdPath)
.then((proposalId) => {
cy.get(openProposals).within(() => {
cy.get('@freeformProposal').then((freeformProposal) => {
cy.get('@rawProposal').then((rawProposal) => {
// 1004-VOTE-008
// 1004-VOTE-034
cy.get(`#${proposalId}`)
.should('contain', freeformProposal.rationale.title)
.should('contain', rawProposal.rationale.title)
.and('be.visible');
cy.get(`#${proposalId}`)
.should(
'contain',
freeformProposal.rationale.description.substring(0, 59)
rawProposal.rationale.description.substring(0, 59)
)
.and('be.visible');
});
@@ -303,70 +251,63 @@ context(
});
});
it('Newly created freeform proposals list - shows open proposals in an open state', function () {
it('Newly created proposals list - shows open proposals in an open state', function () {
// 1004-VOTE-004
// 1004-VOTE-035
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
createRawProposal(this.minProposerBalance);
cy.wait('@proposalSubmissionCompletion')
.its(proposalResponseProposalIdPath)
.then((proposalId) => {
cy.get(openProposals).within(() => {
// 1004-VOTE-035
cy.get(`#${proposalId}`)
.should('contain', proposalId)
.and('contain', 'Open')
.and('be.visible');
cy.get(`#${proposalId}`).within(() => {
cy.get(viewProposalButton).should('be.visible').click();
});
});
cy.get_proposal_information_from_table('ID')
.contains(proposalId)
.and('be.visible');
cy.get_proposal_information_from_table('State')
.contains('STATE_OPEN')
.and('be.visible');
cy.get_proposal_information_from_table('Type')
.contains('NewFreeform')
.and('be.visible');
});
});
it('Newly created freeform proposals list - proposals closest to closing date appear higher in list', function () {
it('Newly created proposals list - proposals closest to closing date appear higher in list', function () {
// 1004-VOTE-005
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
).then(() => {
let proposalHours = [
(Number(this.minCloseHours) + 1).toString(),
this.maxCloseHours,
(Number(this.minCloseHours) + 3).toString(),
(Number(this.minCloseHours) + 2).toString(),
];
for (var index = 0; index < proposalHours.length; index++) {
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body(proposalHours[index]);
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should(
'be.visible'
);
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
}
});
// Ensuring that proposals are not posted in same order as sort order
);
let proposalDays = [
this.minCloseDays + 1,
this.maxCloseDays,
this.minCloseDays + 3,
this.minCloseDays + 2,
];
for (var index = 0; index < proposalDays.length; index++) {
cy.go_to_make_new_proposal(governanceProposalType.RAW);
cy.create_ten_digit_unix_timestamp_for_specified_days(
proposalDays[index]
).then((closingDateTimestamp) => {
cy.enter_raw_proposal_body(closingDateTimestamp);
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should(
'be.visible'
);
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
}
let arrayOfProposals = [];
cy.navigate_to('governance');
cy.wait_for_spinner();
cy.get(proposalDetailsTitle)
.each((proposalTitleElement) => {
arrayOfProposals.push(proposalTitleElement.text());
@@ -380,22 +321,8 @@ context(
});
// Skipping test due to bug: #1320
it.skip('Newly created freeform proposals list - shows proposal parcipitation - both met and not', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
it.skip('Newly created freeform proposals list - shows proposal participation - both met and not', function () {
createFreeformProposal(this.minProposerBalance);
cy.get_submitted_proposal_from_proposal_list()
.as('submittedProposal')
.within(() => {
@@ -430,20 +357,7 @@ context(
// Skipping test due to bug - should be solved when #1223 released
it.skip('Newly created freeform proposal details - shows proposal title and full description', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50').as('freeformProposal');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
createRawProposal(this.minProposerBalance);
cy.wait('@proposalSubmissionCompletion')
.its(proposalResponseProposalIdPath)
.then((proposalId) => {
@@ -452,7 +366,7 @@ context(
cy.get(viewProposalButton).should('be.visible').click();
});
});
cy.get('@freeformProposal').then((freeformProposal) => {
cy.get('@rawProposal').then((freeformProposal) => {
// 1004-VOTE-054
cy.get(proposalDetailsTitle)
.should('contain', freeformProposal.rationale.title)
@@ -464,23 +378,10 @@ context(
});
});
// 1005-todo-PROP-019
// Skipping test due to bug - should be solved when #1223 released
it.skip('Newly created freeform proposal details - shows full link included in description', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50').as('freeformProposal');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
it.skip('Newly created raw proposal details - shows full link included in description', function () {
createRawProposal(this.minProposerBalance);
cy.wait('@proposalSubmissionCompletion')
.its(proposalResponseProposalIdPath)
.then((proposalId) => {
@@ -489,7 +390,7 @@ context(
cy.get(viewProposalButton).should('be.visible').click();
});
});
cy.get('@freeformProposal').then(() => {
cy.get('@rawProposal').then(() => {
// 1004-VOTE-055
cy.get(proposalDetailsDescription)
.should('have.attr', 'href')
@@ -502,61 +403,18 @@ context(
});
});
it('Newly created freeform proposal details - shows open proposal in an open state', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
cy.wait('@proposalSubmissionCompletion')
.its(proposalResponseProposalIdPath)
.then((proposalId) => {
cy.get(openProposals).within(() => {
cy.get(`#${proposalId}`).within(() => {
cy.get(viewProposalButton).should('be.visible').click();
});
});
cy.get_proposal_information_from_table('ID')
.contains(proposalId)
.and('be.visible');
cy.get_proposal_information_from_table('State')
.contains('STATE_OPEN')
.and('be.visible');
cy.get_proposal_information_from_table('Type')
.contains('NewFreeform')
.and('be.visible');
});
});
it('Newly created freeform proposal details - shows proposed and closing dates', function () {
const closingVoteHrs = '72';
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.create_ten_digit_unix_timestamp_for_specified_days('3').then(
(closingDateTimestamp) => {
cy.enter_unique_freeform_proposal_body(closingVoteHrs);
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should(
'be.visible'
);
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_submitted();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
@@ -583,24 +441,10 @@ context(
cy.contains('3 days left to vote').should('be.visible');
});
it('Newly created freeform proposal details - shows default status set to fail', function () {
it('Newly created proposal details - shows default status set to fail', function () {
// 1004-VOTE-037
// 1004-VOTE-040
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
createRawProposal(this.minProposerBalance);
cy.get_submitted_proposal_from_proposal_list().within(() =>
cy.get(viewProposalButton).click()
);
@@ -621,22 +465,8 @@ context(
.should('be.visible');
});
it('Newly created freeform proposal details - ability to vote for proposal - with minimum required tokens associated', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
it('Newly created proposal details - ability to vote for and against proposal - with minimum required tokens associated', function () {
createRawProposal(this.minProposerBalance);
cy.get_submitted_proposal_from_proposal_list()
.as('submittedProposal')
.within(() => cy.get(viewProposalButton).click());
@@ -686,191 +516,28 @@ context(
cy.get_proposal_information_from_table('Number of voting parties')
.should('have.text', '1')
.and('be.visible');
});
it('Newly created freeform proposal details - ability to vote against proposal - with minimum required tokens associated', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
cy.get_submitted_proposal_from_proposal_list()
.as('submittedProposal')
.within(() => cy.get(viewProposalButton).click());
cy.vote_for_proposal('against');
cy.get_governance_proposal_date_format_for_specified_days(
'0',
'shortMonth'
).then((votedDate) => {
// 1004-VOTE-051
cy.contains('You voted:')
.siblings()
.contains('Against')
.siblings()
.contains(votedDate)
.should('be.visible');
});
cy.get(proposalVoteProgressForPercentage)
.contains('0.00%')
.and('be.visible');
cy.get(proposalVoteProgressAgainstPercentage)
.contains('100.00%')
.and('be.visible');
cy.get(proposalVoteProgressForTokens)
.contains('0.00')
.and('be.visible');
cy.get(proposalVoteProgressAgainstTokens)
.contains('1.00')
.and('be.visible');
cy.get_proposal_information_from_table('Tokens for proposal')
.should('have.text', '0.00')
.and('be.visible');
cy.get_proposal_information_from_table('Tokens against proposal')
.should('have.text', parseFloat(this.minProposerBalance).toFixed(2))
.and('be.visible');
cy.get_proposal_information_from_table('Participation required')
.contains(`${this.requiredParticipation}%`)
.should('be.visible');
cy.get_proposal_information_from_table('Majority Required')
.contains(`${parseFloat(this.requiredMajority).toFixed(2)}%`)
.should('be.visible');
cy.get_proposal_information_from_table('Number of voting parties')
.should('have.text', '1')
.and('be.visible');
});
it('Newly created freeform proposal details - ability to change vote from against to for - with minimum required tokens associated', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
cy.get_submitted_proposal_from_proposal_list()
.as('submittedProposal')
.within(() => cy.get(viewProposalButton).click());
cy.vote_for_proposal('against');
// 1004-VOTE-090
cy.get(changeVoteButton).should('be.visible').click();
cy.wait_for_spinner();
cy.vote_for_proposal('for');
cy.get(proposalVoteProgressForPercentage)
.contains('100.00%')
.and('be.visible');
cy.get(proposalVoteProgressAgainstPercentage)
.contains('0.00%')
.and('be.visible');
cy.get(proposalVoteProgressForTokens)
.contains('1.00')
.and('be.visible');
cy.get(proposalVoteProgressAgainstTokens)
.contains('0.00')
.and('be.visible');
// 1004-VOTE-064
cy.get_proposal_information_from_table('Tokens for proposal')
.should('have.text', parseFloat(this.minProposerBalance).toFixed(2))
.and('be.visible');
cy.get_proposal_information_from_table('Tokens against proposal')
.should('have.text', '0.00')
.and('be.visible');
cy.get_proposal_information_from_table('Participation required')
.contains(`${this.requiredParticipation}%`)
.should('be.visible');
cy.get_proposal_information_from_table('Majority Required')
.contains(`${parseFloat(this.requiredMajority).toFixed(2)}%`)
.should('be.visible');
cy.get_proposal_information_from_table('Number of voting parties')
.should('have.text', '1')
.and('be.visible');
});
it('Newly created freeform proposal details - ability to change vote from for to against - with minimum required tokens associated', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
cy.get_submitted_proposal_from_proposal_list()
.as('submittedProposal')
.within(() => cy.get(viewProposalButton).click());
cy.vote_for_proposal('for');
cy.get(changeVoteButton).should('be.visible').click();
cy.wait_for_spinner();
cy.vote_for_proposal('against');
cy.get(proposalVoteProgressForPercentage)
.contains('0.00%')
.and('be.visible');
cy.get(proposalVoteProgressAgainstPercentage)
.contains('100.00%')
.and('be.visible');
cy.get(proposalVoteProgressForTokens)
.contains('0.00')
.and('be.visible');
cy.get(proposalVoteProgressAgainstTokens)
.contains('1.00')
.and('be.visible');
cy.get_proposal_information_from_table('Tokens for proposal')
.should('have.text', '0.00')
.and('be.visible');
cy.get_proposal_information_from_table('Tokens against proposal')
.should('have.text', parseFloat(this.minProposerBalance).toFixed(2))
.and('be.visible');
cy.get_proposal_information_from_table('Participation required')
.contains(`${this.requiredParticipation}%`)
.should('be.visible');
cy.get_proposal_information_from_table('Majority Required')
.contains(`${parseFloat(this.requiredMajority).toFixed(2)}%`)
.should('be.visible');
cy.get_proposal_information_from_table('Number of voting parties')
.should('have.text', '1')
.and('be.visible');
});
it('Newly created freeform proposal details - ability to increase associated tokens - so that vote sways result', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
it('Newly created proposal details - ability to increase associated tokens - so that vote sways result', function () {
createRawProposal(this.minProposerBalance);
cy.get_submitted_proposal_from_proposal_list()
.as('submittedProposal')
.within(() => cy.get(viewProposalButton).click());
@@ -935,7 +602,6 @@ context(
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('40');
cy.get(newProposalSubmitButton).should('be.visible').click();
@@ -948,7 +614,6 @@ context(
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('100000');
cy.get(newProposalSubmitButton).should('be.visible').click();
@@ -962,7 +627,6 @@ context(
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('500000000');
cy.get(newProposalSubmitButton).should('be.visible').click();
@@ -991,15 +655,14 @@ context(
.and('be.visible');
});
it('Unable to create a freeform proposal - when no tokens are associated', function () {
it('Unable to create a proposal - when no tokens are associated', function () {
cy.vega_wallet_teardown();
cy.get(vegaWalletAssociatedBalance, txTimeout).contains(
'0.000000000000000000',
txTimeout
);
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('49');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.go_to_make_new_proposal(governanceProposalType.RAW);
createRawProposal();
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError)
@@ -1009,14 +672,12 @@ context(
.should('be.visible');
});
it('Unable to create a freeform proposal - when some but not enough tokens are associated', function () {
it('Unable to create a proposal - when some but not enough tokens are associated', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance - 0.000001
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('49');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.go_to_make_new_proposal(governanceProposalType.RAW);
createRawProposal(this.minProposerBalance);
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError)
@@ -1032,13 +693,12 @@ context(
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.create_ten_digit_unix_timestamp_for_specified_days('1').then(
(closingDateTimestamp) => {
cy.fixture('/proposals/freeform.json').then((freeformProposal) => {
freeformProposal.terms.closingTimestamp = closingDateTimestamp;
freeformProposal.unexpectfield = `i shouldn't be here`;
freeformProposal.unexpected = `i shouldn't be here`;
let proposalPayload = JSON.stringify(freeformProposal);
cy.get(proposalDetailsTitle).type(
@@ -1056,7 +716,7 @@ context(
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError)
.contains('Unknown field unexpectfield in vega proposal terms')
.contains('Unknown field unexpected in vega proposal terms')
.should('be.visible');
});
@@ -1066,18 +726,15 @@ context(
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.go_to_make_new_proposal(governanceProposalType.RAW);
cy.create_ten_digit_unix_timestamp_for_specified_days('1').then(
(closingDateTimestamp) => {
cy.fixture('/proposals/freeform.json').then((freeformProposal) => {
freeformProposal.terms.closingTimestamp = closingDateTimestamp;
freeformProposal.terms.unexpectedField = `i shouldn't be here`;
let proposalPayload = JSON.stringify(freeformProposal);
cy.fixture('/proposals/raw.json').then((rawProposal) => {
rawProposal.terms.closingTimestamp = closingDateTimestamp;
rawProposal.terms.unexpectedField = `i shouldn't be here`;
let proposalPayload = JSON.stringify(rawProposal);
cy.get(proposalDetailsTitle).type(
freeformProposal.rationale.title
);
cy.get(proposalDetailsTitle).type(rawProposal.rationale.title);
cy.get(proposalDetailsDescription).type(proposalPayload, {
parseSpecialCharSequences: false,
delay: 2,
@@ -1090,24 +747,20 @@ context(
cy.contains('Transaction failed', proposalTimeout).should('be.visible');
cy.get(feedbackError)
.contains('Unknown field unexpectfield in vega proposal terms')
.contains('Unknown field unexpected in vega proposal terms')
.should('be.visible');
});
// Have to skip because #1326 bug doesn't handle below scenario
// 1005-todo-PROP-009
it.skip('Unable to vote on a freeform proposal - when some but not enough vega associated', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_submitted();
cy.wait_for_proposal_sync();
cy.staking_page_disassociate_tokens('0.0001');
cy.get(vegaWallet).within(() => {
@@ -1126,21 +779,8 @@ context(
cy.get(voteButtons).contains('against').should('not.exist');
});
it('Unable to vote on a freeform proposal - when vega wallet disconnected - option to connect from within', function () {
cy.ensure_specified_unstaked_tokens_are_associated(
this.minProposerBalance
);
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
it('Unable to vote on a proposal - when vega wallet disconnected - option to connect from within', function () {
createRawProposal(this.minProposerBalance);
cy.wait_for_spinner();
cy.get('[data-testid="manage-vega-wallet"]').click();
cy.get('[data-testid="disconnect"]').click();
@@ -1171,6 +811,33 @@ context(
cy.contains('You voted: Against').should('be.visible');
});
function createRawProposal(proposerBalance) {
if (proposerBalance)
cy.ensure_specified_unstaked_tokens_are_associated(proposerBalance);
cy.go_to_make_new_proposal('raw proposal');
cy.create_ten_digit_unix_timestamp_for_specified_days('8').then(
(closingDateTimestamp) => {
cy.enter_raw_proposal_body(closingDateTimestamp).as('rawProposal');
}
);
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.wait_for_proposal_submitted();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
}
function createFreeformProposal(proposerBalance) {
cy.ensure_specified_unstaked_tokens_are_associated(proposerBalance);
cy.go_to_make_new_proposal(governanceProposalType.FREEFORM);
cy.enter_unique_freeform_proposal_body('50');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.wait_for_proposal_submitted();
cy.wait_for_proposal_sync();
cy.navigate_to('governance');
cy.wait_for_spinner();
}
after(
'teardown environment to prevent test data bleeding into other tests',
function () {
@@ -0,0 +1,177 @@
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
const proposalValidationDeadline =
'[data-testid="proposal-validation-deadline"]';
const proposalParameterSelect = '[data-testid="proposal-parameter-select"]';
const proposalMarketSelect = '[data-testid="proposal-market-select"]';
const newProposalTitle = '[data-testid="proposal-title"]';
const newProposalDescription = '[data-testid="proposal-description"]';
const newProposalTerms = '[data-testid="proposal-terms"]';
const currentParameterValue =
'[data-testid="selected-proposal-param-current-value"]';
const newProposedParameterValue =
'[data-testid="selected-proposal-param-new-value"]';
const dialogCloseButton = '[data-testid="dialog-close"]';
const inputError = '[data-testid="input-error-text"]';
const epochTimeout = Cypress.env('epochTimeout');
const proposalTimeout = { timeout: 14000 };
const governanceProposalType = {
NETWORK_PARAMETER: 'Network parameter',
NEW_MARKET: 'New market',
UPDATE_MARKET: 'Update market',
NEW_ASSET: 'New asset',
FREEFORM: 'Freeform',
RAW: 'raw proposal',
};
context(
'Governance flow - form validations for different governance proposals',
{ tags: '@slow' },
function () {
before('connect wallets and set approval limit', function () {
cy.vega_wallet_import();
cy.visit('/');
cy.verify_page_header('The $VEGA token');
cy.vega_wallet_connect();
cy.vega_wallet_set_specified_approval_amount('1000');
cy.reload();
cy.wait_for_spinner();
cy.verify_page_header('The $VEGA token');
cy.ethereum_wallet_connect();
});
beforeEach('visit governance tab', function () {
cy.navigate_to('governance');
cy.wait_for_spinner();
cy.intercept('POST', '/query', (req) => {
if (req.body.operationName === 'ProposalEvent') {
req.alias = 'proposalSubmissionCompletion';
}
});
cy.ensure_specified_unstaked_tokens_are_associated('1');
});
it('Able to submit valid update network parameter proposal', function () {
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER);
// 1005-PROP-006
cy.get(newProposalTitle).type('Test update network parameter proposal');
// 1005-PROP-007
cy.get(newProposalDescription).type('E2E test for proposals');
cy.get(proposalParameterSelect).find('option').should('have.length', 109);
cy.get(proposalParameterSelect).select(
'governance_proposal_asset_minEnact'
);
cy.get(currentParameterValue).should('have.value', '2s');
cy.get(newProposedParameterValue).type('5s');
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.wait_for_proposal_submitted();
});
it('Unable to submit network parameter with missing/invalid fields', function () {
cy.navigate_to_page_if_not_already_loaded('governance');
cy.go_to_make_new_proposal(governanceProposalType.NETWORK_PARAMETER);
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.get(inputError).should('have.length', 3);
cy.get(newProposalTitle).type(
'Invalid update network parameter proposal'
);
cy.get(newProposalDescription).type('E2E invalid test for proposals');
cy.get(proposalParameterSelect).select(
'spam_protection_proposal_min_tokens'
);
cy.get(newProposedParameterValue).type('0');
cy.get(proposalVoteDeadline).clear().type('0');
cy.get(newProposalSubmitButton).click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'not.exist'
);
cy.get(proposalVoteDeadline).clear().type('9000');
cy.get(newProposalSubmitButton).click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'not.exist'
);
});
it('Able to submit valid new market proposal', function () {
cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET);
cy.get(newProposalTitle).type('Test new market proposal');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/new-market').then((newMarketProposal) => {
let newMarketPayload = JSON.stringify(newMarketProposal);
cy.get(newProposalTerms).type(newMarketPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.wait_for_proposal_submitted();
});
it('Unable to submit new market proposal with missing/invalid fields', function () {
cy.go_to_make_new_proposal(governanceProposalType.NEW_MARKET);
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.get(inputError).should('have.length', 3);
});
// skipped because of bug #1605
it.skip('Able to submit update market proposal', function () {
const marketId =
'315a8e48db0a292c92b617264728048c82c20efc922c75fd292fc54e5c727c81';
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET);
cy.get(newProposalTitle).type('Test update asset proposal');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.get(proposalMarketSelect).select(marketId);
cy.get('[data-testid="update-market-details"]').within(() => {
cy.get('dd').eq(0).should('have.text', 'Oranges Daily');
cy.get('dd').eq(1).should('have.text', 'ORANGES.24h');
cy.get('dd').eq(2).should('have.text', marketId);
});
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
let newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
cy.get(newProposalTerms).type(newUpdateMarketProposal, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.wait_for_proposal_submitted();
});
it('Able to submit new asset proposal', function () {
cy.go_to_make_new_proposal(governanceProposalType.NEW_ASSET);
cy.get(newProposalTitle).type('Test new asset proposal');
cy.get(newProposalDescription).type('E2E test for proposals');
cy.fixture('/proposals/new-asset').then((newAssetProposal) => {
let newAssetPayload = JSON.stringify(newAssetProposal);
cy.get(newProposalTerms).type(newAssetPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
});
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal waiting for node vote', proposalTimeout).should(
'be.visible'
);
cy.get(dialogCloseButton).click();
});
it('Unable to submit new asset proposal with missing/invalid fields', function () {
cy.go_to_make_new_proposal(governanceProposalType.NEW_ASSET);
cy.get(newProposalSubmitButton).should('be.visible').click();
cy.get(inputError).should('have.length', 3);
cy.get(newProposalTitle).type('Invalid new asset proposal');
cy.get(newProposalDescription).type('Invalid E2E test for proposals');
cy.get(proposalValidationDeadline).clear().type('2');
cy.get(newProposalSubmitButton).click();
cy.contains('Awaiting network confirmation', epochTimeout).should(
'not.exist'
);
});
}
);
@@ -14,9 +14,11 @@ const tokenSubmitButton = '[data-testid="token-input-submit-button"]';
const ethWalletDissociateButton = '[href="/staking/disassociate"]';
const vestingContractSection = '[data-testid="vega-in-vesting-contract"]';
const vegaInWalletSection = '[data-testid="vega-in-wallet"]';
const connectedVegaKey = '[data-testid="connected-vega-key"]';
const associatedKey = '[data-test-id="associated-key"]';
const associatedAmount = '[data-test-id="associated-amount"]';
const disassocitiationWarning = '[data-testid="disassociation-warning"]';
const associateCompleteText = '[data-testid="transaction-complete-body"]';
const disassociationWarning = '[data-testid="disassociation-warning"]';
const vegaWallet = '[data-testid="vega-wallet"]';
context(
@@ -47,7 +49,8 @@ context(
);
it('Able to associate tokens - from wallet', function () {
//1004-ASSO-008
//1004-ASSO-003
//1004-ASSO-005
//1004-ASSO-009
//1004-ASSO-030
//1004-ASSO-012
@@ -162,7 +165,7 @@ context(
cy.get('button').contains('Select a validator to nominate').click();
cy.get(ethWalletDissociateButton).click();
cy.get(disassocitiationWarning).should('contain', warningText);
cy.get(disassociationWarning).should('contain', warningText);
cy.staking_page_disassociate_all_tokens();
@@ -185,6 +188,8 @@ context(
it('Able to associate and disassociate vesting contract tokens', function () {
// 1004-ASSO-006
// 1004-ASSO-007
// 1004-ASSO-018
// 1004-ASSO-024
// 1004-ASSO-023
@@ -268,15 +273,44 @@ context(
});
it('Not able to associate more tokens than owned', function () {
// 1004-ASSO-008
// 1004-ASSO-010
// No warning visible as described in AC, but the button is disabled
cy.get(ethWalletAssociateButton).first().click();
cy.get(associateWalletRadioButton, { timeout: 30000 }).click();
cy.get(tokenSubmitButton, txTimeout).should('be.disabled'); // button disabled with no input
cy.get(tokenAmountInputBox, { timeout: 10000 }).type(6500000);
cy.get(tokenSubmitButton, txTimeout).should('be.disabled');
});
// 1004-ASSO-004
it('Able to associate tokens to different public key of connected vega wallet', function () {
cy.get(ethWalletAssociateButton).first().click();
cy.get(associateWalletRadioButton).click();
cy.get(connectedVegaKey).should(
'have.text',
Cypress.env('vegaWalletPublicKey')
);
cy.get('[data-testid="manage-vega-wallet"]').click();
cy.get('[data-testid="select-keypair-button"]').click();
cy.get(connectedVegaKey).should(
'have.text',
Cypress.env('vegaWalletPublicKey2')
);
cy.staking_page_associate_tokens('2');
cy.get(vegaWallet).within(() => {
cy.get(vegaWalletAssociatedBalance, txTimeout).should('contain', 2.0);
});
cy.get(associateCompleteText).should(
'have.text',
`Vega key ${Cypress.env(
'vegaWalletPublicKey2Short'
)} can now participate in governance and nominate a validator with your associated $VEGA.`
);
});
after(
'teardown environment to prevent test data bleeding into other tests',
function () {
@@ -29,6 +29,7 @@ context(
.and('have.attr', 'href')
.and('equal', governanceDocsUrl);
// 1005-PROP-001
cy.request(governanceDocsUrl)
.its('body')
.then((body) => {
@@ -2,11 +2,15 @@ const newProposalButton = '[data-testid="new-proposal-link"]';
const proposalInformationTableRows = '[data-testid="key-value-table-row"]';
const newProposalTitle = '[data-testid="proposal-title"]';
const newProposalDescription = '[data-testid="proposal-description"]';
const rawProposalData = '[data-testid="proposal-data"]';
const proposalResponseProposalIdPath =
'response.body.data.busEvents.0.event.id';
const voteButtons = '[data-testid="vote-buttons"]';
const txTimeout = Cypress.env('txTimeout');
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
const dialogCloseButton = '[data-testid="dialog-close"]';
const epochTimeout = Cypress.env('epochTimeout');
const proposalTimeout = { timeout: 14000 };
Cypress.Commands.add(
'convert_unix_timestamp_to_governance_data_table_date_format',
@@ -47,44 +51,26 @@ Cypress.Commands.add(
}
);
Cypress.Commands.add('enter_unique_freeform_proposal_body', (timestamp) => {
cy.fixture('/proposals/freeform.json').then((freeformProposal) => {
freeformProposal.terms.closingTimestamp = timestamp;
freeformProposal.rationale.title += timestamp;
let proposalPayload = JSON.stringify(freeformProposal);
Cypress.Commands.add('enter_raw_proposal_body', (timestamp) => {
cy.fixture('/proposals/raw.json').then((rawProposal) => {
rawProposal.terms.closingTimestamp = timestamp;
rawProposal.rationale.title += timestamp;
let proposalPayload = JSON.stringify(rawProposal);
cy.get(newProposalTitle).type(freeformProposal.rationale.title);
cy.get(newProposalDescription).type(proposalPayload, {
cy.get(rawProposalData).type(proposalPayload, {
parseSpecialCharSequences: false,
delay: 2,
});
cy.get(proposalVoteDeadline).clear().click().type(timestamp);
cy.wrap(freeformProposal);
cy.wrap(rawProposal);
});
});
Cypress.Commands.add('get_network_parameters', () => {
let mutation = '{networkParameters {key value}}';
cy.request({
method: 'POST',
url: `http://localhost:3028/query`,
body: {
query: mutation,
},
headers: { 'content-type': 'application/json' },
})
.its(`body.data.networkParameters`)
.then(function (response) {
let object = response.reduce(function (r, e) {
r[e.key] = e.value;
return r;
}, {});
return object;
});
Cypress.Commands.add('enter_unique_freeform_proposal_body', (timestamp) => {
cy.get(newProposalTitle).type(`${timestamp} test freeform proposal`);
cy.get(newProposalDescription).type(
'this is a e2e freeform proposal description'
);
cy.get(proposalVoteDeadline).clear().click().type(timestamp);
});
Cypress.Commands.add('get_submitted_proposal_from_proposal_list', () => {
@@ -165,6 +151,15 @@ Cypress.Commands.add('get_sort_order_of_supplied_array', (suppliedArray) => {
});
Cypress.Commands.add('go_to_make_new_proposal', (proposalType) => {
cy.navigate_to_page_if_not_already_loaded('governance');
cy.get(newProposalButton).should('be.visible').click();
cy.get('li').contains(proposalType).click();
});
Cypress.Commands.add('wait_for_proposal_submitted', () => {
cy.contains('Awaiting network confirmation', epochTimeout).should(
'be.visible'
);
cy.contains('Proposal submitted', proposalTimeout).should('be.visible');
cy.get(dialogCloseButton).click();
});
@@ -20,7 +20,7 @@ const vegaKeySelector = '#vega-key-selector';
const txTimeout = Cypress.env('txTimeout');
const epochTimeout = Cypress.env('epochTimeout');
Cypress.Commands.add('wait_for_begining_of_epoch', () => {
Cypress.Commands.add('wait_for_beginning_of_epoch', () => {
cy.contains('Waiting for next epoch to start', epochTimeout).should(
'not.exist'
);
@@ -34,7 +34,7 @@ Cypress.Commands.add('staking_validator_page_add_stake', (stake) => {
cy.wait_for_spinner();
cy.get(addStakeRadioButton, epochTimeout).click({ force: true });
cy.get(tokenAmountInputBox).type(stake);
cy.wait_for_begining_of_epoch();
cy.wait_for_beginning_of_epoch();
cy.get(tokenSubmitButton, epochTimeout)
.should('be.enabled')
.and('contain', `Add ${stake} $VEGA tokens`)
@@ -47,7 +47,7 @@ Cypress.Commands.add('staking_validator_page_remove_stake', (stake) => {
cy.wait_for_spinner();
cy.get(removeStakeRadioButton, epochTimeout).click();
cy.get(tokenAmountInputBox).type(stake);
cy.wait_for_begining_of_epoch();
cy.wait_for_beginning_of_epoch();
cy.get(tokenSubmitButton)
.should('be.enabled', epochTimeout)
.and('contain', `Remove ${stake} $VEGA tokens at the end of epoch`)
@@ -151,7 +151,7 @@ Cypress.Commands.add(
cy.wait_for_spinner();
cy.contains('Loading...', epochTimeout).should('not.exist');
cy.contains('Total stake this epoch').should('be.visible');
cy.wait_for_begining_of_epoch();
cy.wait_for_beginning_of_epoch();
// below is to ensure validator list is shown
cy.get(stakeValidatorListName, { timeout: 10000 }).should('exist');
cy.get(stakeValidatorListPendingStake, txTimeout).should(
@@ -180,7 +180,7 @@ Cypress.Commands.add(
cy.wait_for_spinner();
cy.contains('Loading...', epochTimeout).should('not.exist');
cy.contains('Total stake this epoch').should('be.visible');
cy.wait_for_begining_of_epoch();
cy.wait_for_beginning_of_epoch();
cy.get(`[row-id="${positionOnList}"]`).within(() => {
cy.get(stakeValidatorListName).should('have.text', expectedValidatorName);
cy.get(stakeValidatorListTotalStake, epochTimeout).should(
@@ -17,7 +17,7 @@ import type {
} from './__generated__/Delegations';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useContracts } from '../../contexts/contracts/contracts-context';
import { isAssetTypeERC20 } from '@vegaprotocol/react-helpers';
import { isAssetTypeERC20 } from '@vegaprotocol/assets';
import { AccountType } from '@vegaprotocol/types';
const DELEGATIONS_QUERY = gql`
@@ -636,6 +636,7 @@
"NewMarketProposal": "New market proposal",
"UpdateMarketProposal": "Update market proposal",
"NewAssetProposal": "New asset proposal",
"UpdateAssetProposal": "Update asset proposal",
"NewFreeformProposal": "New freeform proposal",
"NewRawProposal": "New raw proposal",
"MinProposalRequirements": "You must have at least {{value}} VEGA associated to make a proposal",
@@ -647,6 +648,7 @@
"NewMarket": "New market",
"UpdateMarket": "Update market",
"NewAsset": "New asset",
"UpdateAsset": "Update asset",
"Freeform": "Freeform",
"RawProposal": "Let me choose (raw proposal)",
"UseMin": "Use minimum",
@@ -26,7 +26,7 @@ import {
lastWeek,
nextWeek,
} from '../../test-helpers/mocks';
import type { ProposalsConnection_proposalsConnection_edges_node as ProposalNode } from '@vegaprotocol/governance';
import type { Proposals_proposalsConnection_edges_node as ProposalNode } from '../../proposals/__generated__/Proposals';
const renderComponent = (
proposal: ProposalNode,
@@ -172,7 +172,7 @@ describe('Proposals list item details', () => {
datetime: lastWeek.toString(),
party: {
__typename: 'Party',
id: mockPubkey,
id: mockPubkey.publicKey,
stakingSummary: {
__typename: 'StakingSummary',
currentStakeAvailable: '1000',
@@ -210,7 +210,7 @@ describe('Proposals list item details', () => {
datetime: lastWeek.toString(),
party: {
__typename: 'Party',
id: mockPubkey,
id: mockPubkey.publicKey,
stakingSummary: {
__typename: 'StakingSummary',
currentStakeAvailable: '1000',
@@ -1,4 +1,4 @@
import { render, screen, waitFor } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import { ProposeFreeform } from './propose-freeform';
import { MockedProvider } from '@apollo/client/testing';
import { mockWalletContext } from '../../test-helpers/mocks';
@@ -81,16 +81,14 @@ describe('Propose Freeform', () => {
it('should render the title', async () => {
renderComponent();
await waitFor(() =>
expect(screen.getByText('New freeform proposal')).toBeInTheDocument()
);
expect(
await screen.findByText('New freeform proposal')
).toBeInTheDocument();
});
it('should render the form components', async () => {
renderComponent();
await waitFor(() =>
expect(screen.getByTestId('freeform-proposal-form')).toBeTruthy()
);
expect(await screen.findByTestId('freeform-proposal-form')).toBeTruthy();
expect(screen.getByTestId('min-proposal-requirements')).toBeTruthy();
expect(screen.getByTestId('proposal-docs-link')).toBeTruthy();
expect(screen.getByTestId('proposal-title')).toBeTruthy();
@@ -27,7 +27,7 @@ export interface FreeformProposalFormFields {
proposalReference: string;
}
const docsLink = 'freeform-proposal';
const DOCS_LINK = 'freeform-proposal';
export const ProposeFreeform = () => {
const { params, loading, error } = useNetworkParams([
@@ -76,9 +76,9 @@ export const ProposeFreeform = () => {
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<Link
href={`${VEGA_DOCS_URL}/tutorials/proposals/${docsLink}`}
href={`${VEGA_DOCS_URL}/tutorials/proposals/${DOCS_LINK}`}
target="_blank"
>{`${VEGA_DOCS_URL}/tutorials/proposals/${docsLink}`}</Link>
>{`${VEGA_DOCS_URL}/tutorials/proposals/${DOCS_LINK}`}</Link>
</p>
)}
@@ -1,4 +1,4 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { fireEvent, render, screen } from '@testing-library/react';
import { ProposeNetworkParameter } from './propose-network-parameter';
import { MockedProvider } from '@apollo/client/testing';
import { mockWalletContext } from '../../test-helpers/mocks';
@@ -81,16 +81,16 @@ describe('Propose Network Parameter', () => {
it('should render the correct title', async () => {
renderComponent();
await waitFor(() =>
expect(screen.getByText('Update network parameter proposal')).toBeTruthy()
);
expect(
await screen.findByText('Update network parameter proposal')
).toBeTruthy();
});
it('should render the form components', async () => {
renderComponent();
await waitFor(() =>
expect(screen.getByTestId('network-parameter-proposal-form')).toBeTruthy()
);
expect(
await screen.findByTestId('network-parameter-proposal-form')
).toBeTruthy();
expect(screen.getByTestId('min-proposal-requirements')).toBeTruthy();
expect(screen.getByTestId('proposal-docs-link')).toBeTruthy();
expect(screen.getByTestId('proposal-title')).toBeTruthy();
@@ -103,15 +103,15 @@ describe('Propose Network Parameter', () => {
it('should render the network param select element with no initial value', async () => {
renderComponent();
await waitFor(() =>
expect(screen.getByTestId('proposal-parameter-select')).toHaveValue('')
expect(await screen.findByTestId('proposal-parameter-select')).toHaveValue(
''
);
});
it('should render the current param value and a new value input when the network param select element is changed', async () => {
renderComponent();
await waitFor(() =>
expect(screen.getByTestId('proposal-parameter-select')).toHaveValue('')
expect(await screen.findByTestId('proposal-parameter-select')).toHaveValue(
''
);
fireEvent.change(screen.getByTestId('proposal-parameter-select'), {
@@ -69,7 +69,7 @@ export interface NetworkParameterProposalFormFields {
proposalReference: string;
}
const docsLink = '/network-parameter-proposal';
const DOCS_LINK = '/network-parameter-proposal';
export const ProposeNetworkParameter = () => {
const [selectedNetworkParam, setSelectedNetworkParam] = useState<
@@ -141,9 +141,9 @@ export const ProposeNetworkParameter = () => {
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<Link
href={`${VEGA_DOCS_URL}/tutorials/proposals${docsLink}`}
href={`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}
target="_blank"
>{`${VEGA_DOCS_URL}/tutorials/proposals${docsLink}`}</Link>
>{`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}</Link>
</p>
)}
@@ -1,6 +1,6 @@
import { MockedProvider } from '@apollo/client/testing';
import { MemoryRouter as Router } from 'react-router-dom';
import { render, screen, waitFor } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { mockWalletContext } from '../../test-helpers/mocks';
@@ -81,16 +81,12 @@ describe('Propose New Asset', () => {
it('should render the title', async () => {
renderComponent();
await waitFor(() =>
expect(screen.getByText('New asset proposal')).toBeTruthy()
);
expect(await screen.findByText('New asset proposal')).toBeTruthy();
});
it('should render the form components', async () => {
renderComponent();
await waitFor(() =>
expect(screen.getByTestId('new-asset-proposal-form')).toBeTruthy()
);
expect(await screen.findByTestId('new-asset-proposal-form')).toBeTruthy();
expect(screen.getByTestId('min-proposal-requirements')).toBeTruthy();
expect(screen.getByTestId('proposal-docs-link')).toBeTruthy();
expect(screen.getByTestId('proposal-title')).toBeTruthy();
@@ -7,6 +7,7 @@ import {
getValidationTimestamp,
} from '@vegaprotocol/governance';
import { useEnvironment } from '@vegaprotocol/environment';
import { validateJson } from '@vegaprotocol/react-helpers';
import {
ProposalFormMinRequirements,
ProposalFormTitle,
@@ -32,7 +33,7 @@ export interface NewAssetProposalFormFields {
proposalReference: string;
}
const docsLink = '/new-asset-proposal';
const DOCS_LINK = '/new-asset-proposal';
export const ProposeNewAsset = () => {
const {
@@ -100,9 +101,9 @@ export const ProposeNewAsset = () => {
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<Link
href={`${VEGA_DOCS_URL}/tutorials/proposals${docsLink}`}
href={`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}
target="_blank"
>{`${VEGA_DOCS_URL}/tutorials/proposals${docsLink}`}</Link>
>{`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}</Link>
</p>
)}
@@ -141,20 +142,11 @@ export const ProposeNewAsset = () => {
<ProposalFormTerms
registerField={register('proposalTerms', {
required: t('Required'),
validate: {
validateJson: (value) => {
try {
JSON.parse(value);
return true;
} catch (e) {
return t('Must be valid JSON');
}
},
},
validate: (value) => validateJson(value),
})}
labelOverride={'Terms.newAsset (JSON format)'}
errorMessage={errors?.proposalTerms?.message}
customDocLink={docsLink}
customDocLink={DOCS_LINK}
/>
<ProposalFormVoteAndEnactmentDeadline
@@ -1,4 +1,4 @@
import { render, screen, waitFor } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import { ProposeNewMarket } from './propose-new-market';
import { MockedProvider } from '@apollo/client/testing';
import { mockWalletContext } from '../../test-helpers/mocks';
@@ -81,9 +81,7 @@ describe('Propose New Market', () => {
it('should render the form components', async () => {
renderComponent();
await waitFor(() =>
expect(screen.getByTestId('new-market-proposal-form')).toBeTruthy()
);
expect(await screen.findByTestId('new-market-proposal-form')).toBeTruthy();
expect(screen.getByTestId('min-proposal-requirements')).toBeTruthy();
expect(screen.getByTestId('proposal-docs-link')).toBeTruthy();
expect(screen.getByTestId('proposal-title')).toBeTruthy();
@@ -6,6 +6,7 @@ import {
getEnactmentTimestamp,
} from '@vegaprotocol/governance';
import { useEnvironment } from '@vegaprotocol/environment';
import { validateJson } from '@vegaprotocol/react-helpers';
import {
ProposalFormMinRequirements,
ProposalFormTitle,
@@ -30,7 +31,7 @@ export interface NewMarketProposalFormFields {
proposalReference: string;
}
const docsLink = '/new-market-proposal';
const DOCS_LINK = '/new-market-proposal';
export const ProposeNewMarket = () => {
const {
@@ -95,9 +96,9 @@ export const ProposeNewMarket = () => {
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<Link
href={`${VEGA_DOCS_URL}/tutorials/proposals/${docsLink}`}
href={`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}
target="_blank"
>{`${VEGA_DOCS_URL}/tutorials/proposals/${docsLink}`}</Link>
>{`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}</Link>
</p>
)}
@@ -136,20 +137,11 @@ export const ProposeNewMarket = () => {
<ProposalFormTerms
registerField={register('proposalTerms', {
required: t('Required'),
validate: {
validateJson: (value) => {
try {
JSON.parse(value);
return true;
} catch (e) {
return t('Must be valid JSON');
}
},
},
validate: (value) => validateJson(value),
})}
labelOverride={'Terms.newMarket (JSON format)'}
errorMessage={errors?.proposalTerms?.message}
customDocLink={docsLink}
customDocLink={DOCS_LINK}
/>
<ProposalFormVoteAndEnactmentDeadline
@@ -24,6 +24,7 @@ describe('Propose', () => {
expect(screen.getByText('New market')).toBeTruthy();
expect(screen.getByText('Update market')).toBeTruthy();
expect(screen.getByText('New asset')).toBeTruthy();
expect(screen.getByText('Update asset')).toBeTruthy();
expect(screen.getByText('Freeform')).toBeTruthy();
expect(screen.getByText('Let me choose (raw proposal)')).toBeTruthy();
});
@@ -79,6 +79,16 @@ export const Propose = () => {
</Link>
</p>
</li>
<li>
<p>
<Link
className="underline"
to={`${Routes.GOVERNANCE}/propose/update-asset`}
>
{t('UpdateAsset')}
</Link>
</p>
</li>
<li>
<p>
<Link
@@ -9,6 +9,7 @@ import {
Link,
TextArea,
} from '@vegaprotocol/ui-toolkit';
import { validateJson } from '@vegaprotocol/react-helpers';
import { useProposalSubmit } from '@vegaprotocol/governance';
import {
ProposalFormSubmit,
@@ -74,16 +75,7 @@ export const ProposeRaw = () => {
data-testid="proposal-data"
{...register('rawProposalData', {
required: t('Required'),
validate: {
validateJson: (value) => {
try {
JSON.parse(value);
return true;
} catch (e) {
return t('Must be valid JSON');
}
},
},
validate: (value) => validateJson(value),
})}
/>
{errors.rawProposalData?.message && (
@@ -0,0 +1,4 @@
export {
ProposeUpdateAsset,
ProposeUpdateAsset as default,
} from './propose-update-asset';
@@ -0,0 +1,102 @@
import { MockedProvider } from '@apollo/client/testing';
import { MemoryRouter as Router } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { mockWalletContext } from '../../test-helpers/mocks';
import { ProposeUpdateAsset } from './propose-update-asset';
import type { NetworkParamsQuery } from '@vegaprotocol/web3';
import type { MockedResponse } from '@apollo/client/testing';
import { NETWORK_PARAMETERS_QUERY } from '@vegaprotocol/react-helpers';
jest.mock('@vegaprotocol/environment', () => ({
useEnvironment: () => ({
VEGA_DOCS_URL: 'https://docs.vega.xyz',
}),
}));
const updateAssetNetworkParamsQueryMock: MockedResponse<NetworkParamsQuery> = {
request: {
query: NETWORK_PARAMETERS_QUERY,
},
result: {
data: {
networkParameters: [
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateAsset.maxClose',
value: '8760h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateAsset.maxEnact',
value: '8760h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateAsset.minClose',
value: '1h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateAsset.minEnact',
value: '2h0m0s',
},
{
__typename: 'NetworkParameter',
key: 'governance.proposal.updateAsset.minProposerBalance',
value: '1',
},
{
__typename: 'NetworkParameter',
key: 'spam.protection.proposal.min.tokens',
value: '1000000000000000000',
},
],
},
},
};
const renderComponent = () =>
render(
<Router>
<MockedProvider mocks={[updateAssetNetworkParamsQueryMock]}>
<AppStateProvider>
<VegaWalletContext.Provider value={mockWalletContext}>
<ProposeUpdateAsset />
</VegaWalletContext.Provider>
</AppStateProvider>
</MockedProvider>
</Router>
);
// Note: form submission is tested in propose-raw.spec.tsx. Reusable form
// components are tested in their own directory.
describe('Propose Update Asset', () => {
it('should render successfully', async () => {
const { baseElement } = renderComponent();
await expect(baseElement).toBeTruthy();
});
it('should render the title', async () => {
renderComponent();
expect(await screen.findByText('Update asset proposal')).toBeTruthy();
});
it('should render the form components', async () => {
renderComponent();
expect(
await screen.findByTestId('update-asset-proposal-form')
).toBeTruthy();
expect(screen.getByTestId('min-proposal-requirements')).toBeTruthy();
expect(screen.getByTestId('proposal-docs-link')).toBeTruthy();
expect(screen.getByTestId('proposal-title')).toBeTruthy();
expect(screen.getByTestId('proposal-description')).toBeTruthy();
expect(screen.getByTestId('proposal-terms')).toBeTruthy();
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
});
});
@@ -0,0 +1,182 @@
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import {
useProposalSubmit,
getClosingTimestamp,
getEnactmentTimestamp,
} from '@vegaprotocol/governance';
import { useEnvironment } from '@vegaprotocol/environment';
import { validateJson } from '@vegaprotocol/react-helpers';
import {
ProposalFormMinRequirements,
ProposalFormTitle,
ProposalFormDescription,
ProposalFormTerms,
ProposalFormSubmit,
ProposalFormTransactionDialog,
ProposalFormSubheader,
ProposalFormVoteAndEnactmentDeadline,
} from '../../components/propose';
import { AsyncRenderer, Link } from '@vegaprotocol/ui-toolkit';
import { Heading } from '../../../../components/heading';
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
import { NetworkParams, useNetworkParams } from '@vegaprotocol/react-helpers';
export interface UpdateAssetProposalFormFields {
proposalVoteDeadline: string;
proposalEnactmentDeadline: string;
proposalTitle: string;
proposalDescription: string;
proposalTerms: string;
proposalReference: string;
}
const DOCS_LINK = '/update-asset-proposal';
export const ProposeUpdateAsset = () => {
const {
params,
loading: networkParamsLoading,
error: networkParamsError,
} = useNetworkParams([
NetworkParams.governance_proposal_updateAsset_minClose,
NetworkParams.governance_proposal_updateAsset_maxClose,
NetworkParams.governance_proposal_updateAsset_minEnact,
NetworkParams.governance_proposal_updateAsset_maxEnact,
NetworkParams.governance_proposal_updateAsset_minProposerBalance,
NetworkParams.spam_protection_proposal_min_tokens,
]);
const { VEGA_EXPLORER_URL, VEGA_DOCS_URL } = useEnvironment();
const { t } = useTranslation();
const {
register,
handleSubmit,
formState: { isSubmitting, errors },
} = useForm<UpdateAssetProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const onSubmit = async (fields: UpdateAssetProposalFormFields) => {
await submit({
rationale: {
title: fields.proposalTitle,
description: fields.proposalDescription,
},
terms: {
updateAsset: {
...JSON.parse(fields.proposalTerms),
},
closingTimestamp: getClosingTimestamp(fields.proposalVoteDeadline),
enactmentTimestamp: getEnactmentTimestamp(
fields.proposalVoteDeadline,
fields.proposalEnactmentDeadline
),
},
});
};
return (
<AsyncRenderer
loading={networkParamsLoading}
error={networkParamsError}
data={params}
>
<Heading title={t('UpdateAssetProposal')} />
<VegaWalletContainer>
{() => (
<>
<ProposalFormMinRequirements
minProposerBalance={
params.governance_proposal_updateAsset_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
/>
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<Link
href={`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}
target="_blank"
>{`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}</Link>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreAssetsInfo')}{' '}
<Link
href={`${VEGA_EXPLORER_URL}/assets`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/assets`}</Link>
</p>
)}
<div data-testid="update-asset-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<ProposalFormTitle
registerField={register('proposalTitle', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormSubheader>
{t('UpdateAsset')}
</ProposalFormSubheader>
<ProposalFormTerms
registerField={register('proposalTerms', {
required: t('Required'),
validate: (value) => validateJson(value),
})}
labelOverride={'Terms.updateAsset (JSON format)'}
errorMessage={errors?.proposalTerms?.message}
customDocLink={DOCS_LINK}
/>
<ProposalFormVoteAndEnactmentDeadline
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={params.governance_proposal_updateAsset_minClose}
voteMaxClose={params.governance_proposal_updateAsset_maxClose}
enactmentRegister={register('proposalEnactmentDeadline', {
required: t('Required'),
})}
enactmentErrorMessage={
errors?.proposalEnactmentDeadline?.message
}
enactmentMinClose={
params.governance_proposal_updateAsset_minEnact
}
enactmentMaxClose={
params.governance_proposal_updateAsset_maxEnact
}
/>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
</VegaWalletContainer>
</AsyncRenderer>
);
};
@@ -178,17 +178,17 @@ describe('Propose Update Market', () => {
it('should render the select element with no initial value', async () => {
renderComponent();
await waitFor(() =>
expect(screen.getByText('Update market proposal')).toBeInTheDocument()
);
expect(
await screen.findByText('Update market proposal')
).toBeInTheDocument();
expect(screen.getByTestId('proposal-market-select')).toHaveValue('');
});
it('should render the correct market details when the market select is used', async () => {
renderComponent();
await waitFor(() =>
expect(screen.getByText('Update market proposal')).toBeInTheDocument()
);
expect(
await screen.findByText('Update market proposal')
).toBeInTheDocument();
fireEvent.change(screen.getByTestId('proposal-market-select'), {
target: {
value:
@@ -8,6 +8,7 @@ import {
getEnactmentTimestamp,
} from '@vegaprotocol/governance';
import { useEnvironment } from '@vegaprotocol/environment';
import { validateJson } from '@vegaprotocol/react-helpers';
import {
ProposalFormSubheader,
ProposalFormMinRequirements,
@@ -60,7 +61,7 @@ export interface UpdateMarketProposalFormFields {
proposalReference: string;
}
const docsLink = '/update-market-proposal';
const DOCS_LINK = '/update-market-proposal';
export const ProposeUpdateMarket = () => {
const {
@@ -158,9 +159,9 @@ export const ProposeUpdateMarket = () => {
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<Link
href={`${VEGA_DOCS_URL}/tutorials/proposals${docsLink}`}
href={`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}
target="_blank"
>{`${VEGA_DOCS_URL}/tutorials/proposals${docsLink}`}</Link>
>{`${VEGA_DOCS_URL}/tutorials/proposals${DOCS_LINK}`}</Link>
</p>
)}
@@ -255,20 +256,11 @@ export const ProposeUpdateMarket = () => {
<ProposalFormTerms
registerField={register('proposalTerms', {
required: t('Required'),
validate: {
validateJson: (value) => {
try {
JSON.parse(value);
return true;
} catch (e) {
return t('Must be valid JSON');
}
},
},
validate: (value) => validateJson(value),
})}
labelOverride={t('ProposeUpdateMarketTerms')}
errorMessage={errors?.proposalTerms?.message}
customDocLink={docsLink}
customDocLink={DOCS_LINK}
/>
<ProposalFormVoteAndEnactmentDeadline
@@ -1,11 +1,15 @@
import { NETWORK_PARAMS_QUERY } from '@vegaprotocol/web3';
import type { MockedResponse } from '@apollo/client/testing';
import type { NetworkParamsQuery } from '@vegaprotocol/web3';
import type { PubKey } from '@vegaprotocol/wallet';
export const mockPubkey = '0x123';
export const mockPubkey: PubKey = {
publicKey: '0x123',
name: 'test key 1',
};
export const mockWalletContext = {
pubKey: mockPubkey,
pubKey: mockPubkey.publicKey,
pubKeys: [mockPubkey],
sendTx: jest.fn().mockReturnValue(Promise.resolve(null)),
connect: jest.fn(),
+11
View File
@@ -158,6 +158,13 @@ const LazyGovernanceProposeNewAsset = React.lazy(
)
);
const LazyGovernanceProposeUpdateAsset = React.lazy(
() =>
import(
/* webpackChunkName: "route-governance-propose-update-asset", webpackPrefetch: true */ './governance/propose/update-asset'
)
);
const LazyGovernanceProposeFreeform = React.lazy(
() =>
import(
@@ -273,6 +280,10 @@ const routerConfig = [
element: <LazyGovernanceProposeUpdateMarket />,
},
{ path: 'new-asset', element: <LazyGovernanceProposeNewAsset /> },
{
path: 'update-asset',
element: <LazyGovernanceProposeUpdateAsset />,
},
{ path: 'freeform', element: <LazyGovernanceProposeFreeform /> },
{ path: 'raw', element: <LazyGovernanceProposeRaw /> },
],
+7 -2
View File
@@ -5,6 +5,7 @@ import { Heading } from '../../components/heading';
import { SplashLoader } from '../../components/splash-loader';
import { VegaWalletContainer } from '../../components/vega-wallet-container';
import {
PendingWithdrawalsTable,
useWithdrawals,
WithdrawalDialogs,
WithdrawalsTable,
@@ -30,7 +31,7 @@ const Withdrawals = ({ name }: RouteChildProps) => {
const WithdrawPendingContainer = () => {
const [withdrawDialog, setWithdrawDialog] = useState(false);
const { t } = useTranslation();
const { withdrawals, loading, error } = useWithdrawals();
const { pending, completed, loading, error } = useWithdrawals();
if (error) {
return (
@@ -58,7 +59,11 @@ const WithdrawPendingContainer = () => {
<p>{t('withdrawalsText')}</p>
<p className="mb-8">{t('withdrawalsPreparedWarningText')}</p>
<div className="w-full h-[500px]">
<WithdrawalsTable withdrawals={withdrawals} />
{pending && pending.length > 0 && (
<PendingWithdrawalsTable rowData={pending} />
)}
<h4 className="pt-3 pb-1">{t('Withdrawal history')}</h4>
<WithdrawalsTable rowData={completed} />
</div>
<WithdrawalDialogs
withdrawDialog={withdrawDialog}
@@ -1,5 +1,5 @@
import { aliasQuery } from '@vegaprotocol/cypress';
import { generateDepositPage } from '../support/mocks/generate-deposit-page';
import { generateAssets } from '../support/mocks/generate-assets';
import { generateNetworkParameters } from '../support/mocks/generate-network-parameters';
const connectEthWalletBtn = 'connect-eth-wallet-btn';
@@ -14,7 +14,7 @@ describe('deposit form validation', { tags: '@smoke' }, () => {
cy.mockGQLSubscription();
cy.mockGQL((req) => {
aliasQuery(req, 'NetworkParamsQuery', generateNetworkParameters());
aliasQuery(req, 'DepositPage', generateDepositPage());
aliasQuery(req, 'Assets', generateAssets());
});
cy.visit('/portfolio/deposit');
@@ -22,7 +22,7 @@ describe('deposit form validation', { tags: '@smoke' }, () => {
cy.getByTestId(connectEthWalletBtn).click();
cy.getByTestId('web3-connector-MetaMask').click();
cy.wait('@DepositPage');
cy.wait('@Assets');
});
it('handles empty fields', () => {
@@ -41,7 +41,7 @@ describe('deposit form validation', { tags: '@smoke' }, () => {
// Deposit amount smaller than minimum viable for selected asset
// Select an amount so that we have a known decimal places value to work with
cy.get(assetSelectField).select('Asset 0');
cy.get(assetSelectField).select('Euro');
cy.get(amountField)
.clear()
.type('0.00000000000000000000000000000000001')
@@ -115,7 +115,7 @@ describe('markets table', { tags: '@regression' }, () => {
.should('have.attr', 'href')
.and(
'include',
'https://docs.fairground.vega.xyz/docs/trading-questions/#auctions-what-is-a-liquidity-monitoring-auction'
'https://docs.vega.xyz/docs/testnet/concepts/trading-on-vega/trading-modes#auction-type-liquidity-monitoring'
);
});
@@ -42,7 +42,6 @@ describe('orders', { tags: '@smoke' }, () => {
it('renders orders', () => {
cy.getByTestId('tab-orders').should('be.visible');
expect(subscriptionMocks.OrderSub).to.be.calledOnce;
cy.getByTestId('tab-orders').within(() => {
cy.get(`[col-id='${orderSymbol}']`).each(($symbol) => {
@@ -1,9 +1,9 @@
import { aliasQuery } from '@vegaprotocol/cypress';
import { connectEthereumWallet } from '../support/ethereum-wallet';
import { generateAccounts } from '../support/mocks/generate-accounts';
import { generateChainId } from '../support/mocks/generate-chain-id';
import { generateAccounts } from '../support/mocks/generate-accounts';
import { generateAssets } from '../support/mocks/generate-assets';
import { generateNetworkParameters } from '../support/mocks/generate-network-parameters';
import { generateWithdrawFormQuery } from '../support/mocks/generate-withdraw-page-query';
import { generateWithdrawals } from '../support/mocks/generate-withdrawals';
import { connectVegaWallet } from '../support/vega-wallet';
@@ -24,7 +24,7 @@ describe('withdraw', { tags: '@smoke' }, () => {
aliasQuery(req, 'ChainId', generateChainId());
aliasQuery(req, 'Withdrawals', generateWithdrawals());
aliasQuery(req, 'NetworkParamsQuery', generateNetworkParameters());
aliasQuery(req, 'WithdrawFormQuery', generateWithdrawFormQuery());
aliasQuery(req, 'Assets', generateAssets());
aliasQuery(req, 'Accounts', generateAccounts());
});
cy.mockGQLSubscription();
@@ -39,7 +39,8 @@ describe('withdraw', { tags: '@smoke' }, () => {
connectEthereumWallet();
cy.getByTestId('withdraw-dialog-button').click();
cy.wait('@WithdrawFormQuery');
cy.wait('@Accounts');
cy.wait('@Assets');
});
it('form validation', () => {
@@ -1,6 +1,6 @@
import merge from 'lodash/merge';
import type { AccountsQuery, AssetsQuery } from '@vegaprotocol/accounts';
import { AccountType, Schema as Types } from '@vegaprotocol/types';
import type { AccountsQuery } from '@vegaprotocol/accounts';
import { AccountType } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
export const generateAccounts = (
@@ -70,48 +70,19 @@ export const generateAccounts = (
id: 'asset-0',
},
},
// account to withdraw Sepolia tBTC
{
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
market: null,
asset: {
__typename: 'Asset',
id: 'cee709223217281d7893b650850ae8ee8a18b7539b5658f9b4cc24de95dd18ad',
},
},
],
},
};
return merge(defaultAccounts, override);
};
export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
const defaultAssets: AssetsQuery = {
assetsConnection: {
edges: [
{
node: {
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
name: 'Euro',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
name: 'DAI',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-0',
symbol: 'AST0',
decimals: 5,
name: 'Asto',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
],
},
};
return merge(defaultAssets, override);
};
@@ -0,0 +1,90 @@
import merge from 'lodash/merge';
import type { AssetsQuery } from '@vegaprotocol/assets';
import { Schema as Types } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
const defaultAssets: AssetsQuery = {
assetsConnection: {
edges: [
{
node: {
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
name: 'Euro',
source: {
__typename: 'ERC20',
contractAddress: '0x0158031158Bb4dF2AD02eAA31e8963E84EA978a4',
},
quantum: '1',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
name: 'DAI',
source: {
__typename: 'ERC20',
contractAddress: '0x26223f9C67871CFcEa329975f7BC0C9cB8FBDb9b',
},
quantum: '1',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-0',
symbol: 'AST0',
decimals: 5,
name: 'Asto',
source: {
__typename: 'BuiltinAsset',
},
quantum: '1',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
// NOTE: These assets ids and contract addresses are real assets on Sepolia, this is needed
// because we don't currently mock our seplia infura provider. If we change network these will
// need to be updated
{
node: {
id: 'cee709223217281d7893b650850ae8ee8a18b7539b5658f9b4cc24de95dd18ad',
symbol: 'tBTC',
name: 'Sepolia tBTC',
decimals: 5,
status: Types.AssetStatus.STATUS_ENABLED,
source: {
__typename: 'ERC20',
contractAddress: '0x1d525fB145Af5c51766a89706C09fE07E6058D1D',
},
quantum: '1',
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: 'c9fe6fc24fce121b2cc72680543a886055abb560043fda394ba5376203b7527d',
symbol: 'tUSDC',
name: 'Sepolia tUSDC',
decimals: 5,
status: Types.AssetStatus.STATUS_ENABLED,
source: {
__typename: 'ERC20',
contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d81',
},
quantum: '1',
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
],
},
};
return merge(defaultAssets, override);
};
@@ -1,93 +0,0 @@
import { AssetStatus } from '@vegaprotocol/types';
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
export const generateDepositPage = (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
override?: PartialDeep<any>
) => {
const defaultResult = {
assetsConnection: {
edges: [
{
node: {
id: 'asset-0',
symbol: 'AST0',
name: 'Asset 0',
decimals: 5,
status: AssetStatus.STATUS_ENABLED,
source: {
__typename: 'ERC20',
contractAddress: '0x5E4b9aDA947130Fc320a144cd22bC1641e5c9d81',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: 'asset-1',
symbol: 'AST1',
name: 'Asset 1',
decimals: 5,
status: AssetStatus.STATUS_ENABLED,
source: {
__typename: 'ERC20',
contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d81',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: 'asset-2',
symbol: 'AST2',
name: 'Asset 2',
decimals: 5,
status: AssetStatus.STATUS_PENDING_LISTING,
source: {
__typename: 'ERC20',
contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d82',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: 'asset-3',
symbol: 'AST3',
name: 'Asset 3',
decimals: 5,
status: AssetStatus.STATUS_PROPOSED,
source: {
__typename: 'ERC20',
contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d83',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
{
node: {
id: 'asset-4',
symbol: 'AST4',
name: 'Asset 4',
decimals: 5,
status: AssetStatus.STATUS_REJECTED,
source: {
__typename: 'ERC20',
contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d84',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
},
],
__typename: 'AssetsConnection',
},
};
return merge(defaultResult, override);
};
@@ -1,15 +1,15 @@
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
import type {
Positions,
Positions_party_positionsConnection_edges_node,
Margins,
PositionsQuery,
PositionFieldsFragment,
MarginsQuery,
} from '@vegaprotocol/positions';
export const generatePositions = (
override?: PartialDeep<Positions>
): Positions => {
const nodes: Positions_party_positionsConnection_edges_node[] = [
override?: PartialDeep<PositionsQuery>
): PositionsQuery => {
const nodes: PositionFieldsFragment[] = [
{
__typename: 'Position',
realisedPNL: '0',
@@ -48,7 +48,7 @@ export const generatePositions = (
},
];
const defaultResult: Positions = {
const defaultResult: PositionsQuery = {
party: {
__typename: 'Party',
id: Cypress.env('VEGA_PUBLIC_KEY'),
@@ -67,7 +67,7 @@ export const generatePositions = (
return merge(defaultResult, override);
};
export const generateMargins = (): Margins => {
export const generateMargins = (): MarginsQuery => {
return {
party: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
@@ -1,77 +0,0 @@
import { AccountType, AssetStatus } from '@vegaprotocol/types';
import type {
WithdrawFormQuery,
WithdrawFormQuery_assetsConnection_edges,
WithdrawFormQuery_party_accounts,
WithdrawFormQuery_party_withdrawals,
} from '@vegaprotocol/withdraws';
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
export const generateWithdrawFormQuery = (
override?: PartialDeep<WithdrawFormQuery>
): WithdrawFormQuery => {
const withdrawal: WithdrawFormQuery_party_withdrawals = {
id: 'withdrawal-0',
txHash: null,
__typename: 'Withdrawal',
};
// NOTE: These assets ids and contract addresses are real assets on Sepolia, this is needed
// because we don't currently mock our seplia infura provider. If we change network these will
// need to be updated
const assetEdge1: WithdrawFormQuery_assetsConnection_edges = {
node: {
id: 'cee709223217281d7893b650850ae8ee8a18b7539b5658f9b4cc24de95dd18ad',
symbol: 'tBTC',
name: 'Sepolia tBTC',
decimals: 5,
status: AssetStatus.STATUS_ENABLED,
source: {
__typename: 'ERC20',
contractAddress: '0x1d525fB145Af5c51766a89706C09fE07E6058D1D',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
};
const assetEdge2: WithdrawFormQuery_assetsConnection_edges = {
node: {
id: 'c9fe6fc24fce121b2cc72680543a886055abb560043fda394ba5376203b7527d',
symbol: 'tUSDC',
name: 'Sepolia tUSDC',
decimals: 5,
status: AssetStatus.STATUS_ENABLED,
source: {
__typename: 'ERC20',
contractAddress: '0x444b9aDA947130Fc320a144cd22bC1641e5c9d81',
},
__typename: 'Asset',
},
__typename: 'AssetEdge',
};
const account: WithdrawFormQuery_party_accounts = {
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
asset: {
__typename: 'Asset',
id: assetEdge1.node.id,
symbol: 'AST0',
},
__typename: 'Account',
};
const defaultResult = {
party: {
id: 'party-0',
withdrawals: [withdrawal],
accounts: [account],
__typename: 'Party',
},
assetsConnection: {
__typename: 'AssetsConnection',
edges: [assetEdge1, assetEdge2],
},
};
return merge(defaultResult, override);
};
+2 -1
View File
@@ -1,7 +1,8 @@
import { aliasQuery } from '@vegaprotocol/cypress';
import type { MarketState } from '@vegaprotocol/types';
import type { CyHttpMessages } from 'cypress/types/net-stubbing';
import { generateAccounts, generateAssets } from './mocks/generate-accounts';
import { generateAccounts } from './mocks/generate-accounts';
import { generateAssets } from './mocks/generate-assets';
import { generateCandles } from './mocks/generate-candles';
import { generateChart } from './mocks/generate-chart';
import { generateDealTicketQuery } from './mocks/generate-deal-ticket-query';
@@ -15,7 +15,7 @@ import type {
MarketWithData,
} from '@vegaprotocol/market-list';
import { useVegaWallet } from '@vegaprotocol/wallet';
import type { Positions_party_positionsConnection_edges_node } from '@vegaprotocol/positions';
import type { PositionFieldsFragment } from '@vegaprotocol/positions';
import { positionsDataProvider } from '@vegaprotocol/positions';
import {
SelectMarketTableHeader,
@@ -79,7 +79,7 @@ export const SelectAllMarketsTableBody = ({
tableColumns = (market) => columns(market, onSelect, onCellClick),
}: {
markets?: Market[] | null;
positions?: Positions_party_positionsConnection_edges_node[];
positions?: PositionFieldsFragment[];
title?: string;
onSelect: (id: string) => void;
onCellClick: OnCellClickHandler;
-16
View File
@@ -1,16 +0,0 @@
import { gql } from '@apollo/client';
export const ASSET_FRAGMENT = gql`
fragment AssetFields on Asset {
id
symbol
name
decimals
status
source {
... on ERC20 {
contractAddress
}
}
}
`;
@@ -4,6 +4,7 @@ import {
addDecimalsFormatNumber,
t,
titlefy,
useYesterday,
} from '@vegaprotocol/react-helpers';
import { Interval } from '@vegaprotocol/types';
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
@@ -113,12 +114,12 @@ const MarketPage = ({ id }: { id?: string }) => {
}
};
const yesterday = useYesterday();
// Cache timestamp for yesterday to prevent full unmount of market page when
// a rerender occurs
const yTimestamp = useMemo(() => {
const yesterday = Math.round(new Date().getTime() / 1000) - 24 * 3600;
return new Date(yesterday * 1000).toISOString();
}, []);
return new Date(yesterday).toISOString();
}, [yesterday]);
const variables = useMemo(
() => ({
@@ -1,17 +0,0 @@
query DepositPage {
assetsConnection {
edges {
node {
id
symbol
name
decimals
source {
... on ERC20 {
contractAddress
}
}
}
}
}
}
@@ -1,75 +0,0 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
import { AssetStatus } from "@vegaprotocol/types";
// ====================================================
// GraphQL query operation: DepositPage
// ====================================================
export interface DepositPage_assetsConnection_edges_node_source_BuiltinAsset {
__typename: "BuiltinAsset";
}
export interface DepositPage_assetsConnection_edges_node_source_ERC20 {
__typename: "ERC20";
/**
* The address of the ERC20 contract
*/
contractAddress: string;
}
export type DepositPage_assetsConnection_edges_node_source = DepositPage_assetsConnection_edges_node_source_BuiltinAsset | DepositPage_assetsConnection_edges_node_source_ERC20;
export interface DepositPage_assetsConnection_edges_node {
__typename: "Asset";
/**
* The ID of the asset
*/
id: string;
/**
* The symbol of the asset (e.g: GBP)
*/
symbol: string;
/**
* The full name of the asset (e.g: Great British Pound)
*/
name: string;
/**
* The precision of the asset. Should match the decimal precision of the asset on its native chain, e.g: for ERC20 assets, it is often 18
*/
decimals: number;
/**
* The status of the asset in the Vega network
*/
status: AssetStatus;
/**
* The origin source of the asset (e.g: an ERC20 asset)
*/
source: DepositPage_assetsConnection_edges_node_source;
}
export interface DepositPage_assetsConnection_edges {
__typename: "AssetEdge";
/**
* The asset information
*/
node: DepositPage_assetsConnection_edges_node;
}
export interface DepositPage_assetsConnection {
__typename: "AssetsConnection";
/**
* The assets
*/
edges: (DepositPage_assetsConnection_edges | null)[] | null;
}
export interface DepositPage {
/**
* The list of all assets in use in the Vega network or the specified asset if ID is provided
*/
assetsConnection: DepositPage_assetsConnection | null;
}
@@ -1,57 +0,0 @@
import { Schema as Types } from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type DepositPageQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type DepositPageQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string } } } | null> | null } | null };
export const DepositPageDocument = gql`
query DepositPage {
assetsConnection {
edges {
node {
id
symbol
name
decimals
source {
... on ERC20 {
contractAddress
}
}
}
}
}
}
`;
/**
* __useDepositPageQuery__
*
* To run a query within a React component, call `useDepositPageQuery` and pass it any options that fit your needs.
* When your component renders, `useDepositPageQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useDepositPageQuery({
* variables: {
* },
* });
*/
export function useDepositPageQuery(baseOptions?: Apollo.QueryHookOptions<DepositPageQuery, DepositPageQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<DepositPageQuery, DepositPageQueryVariables>(DepositPageDocument, options);
}
export function useDepositPageLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<DepositPageQuery, DepositPageQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<DepositPageQuery, DepositPageQueryVariables>(DepositPageDocument, options);
}
export type DepositPageQueryHookResult = ReturnType<typeof useDepositPageQuery>;
export type DepositPageLazyQueryHookResult = ReturnType<typeof useDepositPageLazyQuery>;
export type DepositPageQueryResult = Apollo.QueryResult<DepositPageQuery, DepositPageQueryVariables>;
@@ -1,37 +1,24 @@
import { gql } from '@apollo/client';
import { PageQueryContainer } from '../../../components/page-query-container';
import type { DepositPage } from './__generated__/DepositPage';
import { DepositManager } from '@vegaprotocol/deposits';
import { getEnabledAssets, t } from '@vegaprotocol/react-helpers';
import { useDataProvider, t } from '@vegaprotocol/react-helpers';
import { enabledAssetsProvider } from '@vegaprotocol/assets';
import { useEnvironment } from '@vegaprotocol/environment';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { ASSET_FRAGMENT } from '../../../lib/query-fragments';
const DEPOSIT_PAGE_QUERY = gql`
${ASSET_FRAGMENT}
query DepositPage {
assetsConnection {
edges {
node {
...AssetFields
}
}
}
}
`;
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
/**
* Fetches data required for the Deposit page
*/
export const DepositContainer = () => {
const { VEGA_ENV } = useEnvironment();
const { data, error, loading } = useDataProvider({
dataProvider: enabledAssetsProvider,
});
return (
<PageQueryContainer<DepositPage>
query={DEPOSIT_PAGE_QUERY}
render={(data) => {
const assets = getEnabledAssets(data);
if (!assets.length) {
<AsyncRenderer
data={data}
error={error}
loading={loading}
render={(assets) => {
if (!assets || !assets.length) {
return (
<Splash>
<p>{t('No assets on this network')}</p>
@@ -1,5 +1,6 @@
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
import {
PendingWithdrawalsTable,
useWithdrawals,
WithdrawalDialogs,
WithdrawalsTable,
@@ -10,7 +11,7 @@ import { VegaWalletContainer } from '../../components/vega-wallet-container';
import { Web3Container } from '@vegaprotocol/web3';
export const WithdrawalsContainer = () => {
const { withdrawals, loading, error } = useWithdrawals();
const { pending, completed, loading, error } = useWithdrawals();
const [withdrawDialog, setWithdrawDialog] = useState(false);
return (
@@ -25,17 +26,27 @@ export const WithdrawalsContainer = () => {
onClick={() => setWithdrawDialog(true)}
data-testid="withdraw-dialog-button"
>
{t('Withdraw')}
{t('Make withdrawal')}
</Button>
</header>
<div>
<div className="h-full px-4">
<AsyncRenderer
data={withdrawals}
data={{ pending, completed }}
loading={loading}
error={error}
render={(data) => {
return <WithdrawalsTable withdrawals={data} />;
}}
render={({ pending, completed }) => (
<>
{pending && pending.length > 0 && (
<>
<h4 className="pt-3 pb-1">{t('Pending withdrawals')}</h4>
<PendingWithdrawalsTable rowData={pending} />
</>
)}
<h4 className="pt-3 pb-1">{t('Withdrawal history')}</h4>
<WithdrawalsTable rowData={completed} />
</>
)}
/>
</div>
</div>
-19
View File
@@ -26,22 +26,3 @@ subscription AccountEvents($partyId: ID!) {
marketId
}
}
fragment AssetsFields on Asset {
id
name
symbol
decimals
quantum
status
}
query Assets {
assetsConnection {
edges {
node {
...AssetsFields
}
}
}
}
@@ -19,13 +19,6 @@ export type AccountEventsSubscriptionVariables = Types.Exact<{
export type AccountEventsSubscription = { __typename?: 'Subscription', accounts: Array<{ __typename?: 'AccountUpdate', type: Types.AccountType, balance: string, assetId: string, marketId?: string | null }> };
export type AssetsFieldsFragment = { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus };
export type AssetsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type AssetsQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus } } | null> | null } | null };
export const AccountFieldsFragmentDoc = gql`
fragment AccountFields on Account {
type
@@ -38,16 +31,6 @@ export const AccountFieldsFragmentDoc = gql`
}
}
`;
export const AssetsFieldsFragmentDoc = gql`
fragment AssetsFields on Asset {
id
name
symbol
decimals
quantum
status
}
`;
export const AccountsDocument = gql`
query Accounts($partyId: ID!) {
party(id: $partyId) {
@@ -118,42 +101,4 @@ export function useAccountEventsSubscription(baseOptions: Apollo.SubscriptionHoo
return Apollo.useSubscription<AccountEventsSubscription, AccountEventsSubscriptionVariables>(AccountEventsDocument, options);
}
export type AccountEventsSubscriptionHookResult = ReturnType<typeof useAccountEventsSubscription>;
export type AccountEventsSubscriptionResult = Apollo.SubscriptionResult<AccountEventsSubscription>;
export const AssetsDocument = gql`
query Assets {
assetsConnection {
edges {
node {
...AssetsFields
}
}
}
}
${AssetsFieldsFragmentDoc}`;
/**
* __useAssetsQuery__
*
* To run a query within a React component, call `useAssetsQuery` and pass it any options that fit your needs.
* When your component renders, `useAssetsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useAssetsQuery({
* variables: {
* },
* });
*/
export function useAssetsQuery(baseOptions?: Apollo.QueryHookOptions<AssetsQuery, AssetsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<AssetsQuery, AssetsQueryVariables>(AssetsDocument, options);
}
export function useAssetsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AssetsQuery, AssetsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<AssetsQuery, AssetsQueryVariables>(AssetsDocument, options);
}
export type AssetsQueryHookResult = ReturnType<typeof useAssetsQuery>;
export type AssetsLazyQueryHookResult = ReturnType<typeof useAssetsLazyQuery>;
export type AssetsQueryResult = Apollo.QueryResult<AssetsQuery, AssetsQueryVariables>;
export type AccountEventsSubscriptionResult = Apollo.SubscriptionResult<AccountEventsSubscription>;
@@ -8,7 +8,6 @@ import type {
AccountFieldsFragment,
AccountsQuery,
AccountEventsSubscription,
AssetsFieldsFragment,
} from './__generated___/Accounts';
import {
makeDataProvider,
@@ -17,7 +16,8 @@ import {
import { AccountType } from '@vegaprotocol/types';
import type { Market } from '@vegaprotocol/market-list';
import { marketsProvider } from '@vegaprotocol/market-list';
import { assetProvider } from './asset-data-provider';
import type { AssetsFieldsFragment } from '@vegaprotocol/assets';
import { assetsProvider } from '@vegaprotocol/assets';
function isAccount(
account:
@@ -77,7 +77,7 @@ const getDelta = (
subscriptionData: AccountEventsSubscription
): AccountEventsSubscription['accounts'] => subscriptionData.accounts;
export const accountsBasedDataProvider = makeDataProvider<
export const accountsOnlyDataProvider = makeDataProvider<
AccountsQuery,
AccountFieldsFragment[],
AccountEventsSubscription,
@@ -114,10 +114,12 @@ const getTotalBalance = (accounts: AccountFieldsFragment[]) =>
accounts.reduce((acc, a) => acc + BigInt(a.balance), BigInt(0));
export const getAccountData = (data: Account[]): AccountFields[] => {
return getAssetIds(data).map((assetId) => {
const accounts = data.filter((a) => a.asset.id === assetId);
return accounts && getAssetAccountAggregation(accounts, assetId);
});
return getAssetIds(data)
.map((assetId) => {
const accounts = data.filter((a) => a.asset.id === assetId);
return accounts && getAssetAccountAggregation(accounts, assetId);
})
.filter((a) => a.deposited !== '0'); // filter empty accounts
};
const getAssetAccountAggregation = (
@@ -150,12 +152,13 @@ const getAssetAccountAggregation = (
deposited: balanceAccount.deposited,
available: balanceAccount.available,
used: a.balance,
}));
}))
.filter((a) => a.used !== '0');
return { ...balanceAccount, breakdown };
};
export const accountsDataProvider = makeDerivedDataProvider<Account[], never>(
[accountsBasedDataProvider, marketsProvider, assetProvider],
[accountsOnlyDataProvider, marketsProvider, assetsProvider],
([accounts, markets, assets]): Account[] | null => {
return accounts
? accounts
+1 -1
View File
@@ -1,4 +1,4 @@
import type { Asset } from '@vegaprotocol/react-helpers';
import type { Asset } from '@vegaprotocol/assets';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react';
@@ -38,7 +38,7 @@ describe('AccountsTable', () => {
<AccountTable rowData={singleRowData} onClickAsset={() => null} />
);
});
const expectedHeaders = ['Asset', 'Deposited', 'Used', '', ''];
const expectedHeaders = ['Asset', 'Total', 'Used', '', ''];
const headers = await screen.findAllByRole('columnheader');
expect(headers).toHaveLength(expectedHeaders.length);
expect(
+8 -3
View File
@@ -1,6 +1,6 @@
import { forwardRef, useState } from 'react';
import type { ValueFormatterParams } from 'ag-grid-community';
import type { Asset } from '@vegaprotocol/react-helpers';
import type { Asset } from '@vegaprotocol/assets';
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
import type {
ValueProps,
@@ -109,8 +109,11 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
maxWidth={300}
/>
<AgGridColumn
headerName={t('Deposited')}
headerName={t('Total')}
field="deposited"
headerTooltip={t(
'This is the total amount of collateral used plus the amount available in your general account.'
)}
valueFormatter={({
value,
data,
@@ -125,6 +128,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
headerName={t('Used')}
field="used"
flex={2}
minWidth={150}
maxWidth={500}
headerComponentParams={progressBarHeaderComponentParams}
cellRendererSelector={progressBarCellRendererSelector}
@@ -133,7 +137,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
<AgGridColumn
headerName=""
field="breakdown"
maxWidth={150}
minWidth={150}
cellRenderer={({
value,
}: VegaICellRendererParams<AccountFields, 'breakdown'>) => {
@@ -154,6 +158,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
colId="transact"
headerName=""
sortable={false}
minWidth={250}
cellRenderer={({
data,
}: VegaICellRendererParams<AccountFields>) => {
@@ -1,21 +0,0 @@
import { makeDataProvider } from '@vegaprotocol/react-helpers';
import { AssetsDocument } from './__generated___/Accounts';
import type {
AssetsQuery,
AssetsFieldsFragment,
} from './__generated___/Accounts';
const getData = (responseData: AssetsQuery) =>
responseData.assetsConnection?.edges
?.filter((e) => Boolean(e?.node))
.map((e) => e?.node as AssetsFieldsFragment) ?? null;
export const assetProvider = makeDataProvider<
AssetsQuery,
AssetsFieldsFragment[] | null,
never,
never
>({
query: AssetsDocument,
getData,
});
@@ -37,10 +37,10 @@ describe('BreakdownTable', () => {
render(<BreakdownTable data={singleRowData} />);
});
const headers = await screen.findAllByRole('columnheader');
expect(headers).toHaveLength(5);
expect(headers).toHaveLength(4);
expect(
headers.map((h) => h.querySelector('[ref="eText"]')?.textContent?.trim())
).toEqual(['Account type', 'Market', 'Used', 'Deposited', 'Balance']);
).toEqual(['Account type', 'Market', 'Used', 'Balance']);
});
it('should apply correct formatting', async () => {
-15
View File
@@ -74,21 +74,6 @@ const BreakdownTable = forwardRef<AgGridReact, BreakdownTableProps>(
cellRendererSelector={progressBarCellRendererSelector}
valueFormatter={progressBarValueFormatter}
/>
<AgGridColumn
headerName={t('Deposited')}
field="deposited"
valueFormatter={({
value,
data,
}: VegaValueFormatterParams<AccountFields, 'deposited'>) => {
if (data && data.asset) {
return addDecimalsFormatNumber(value, data.asset.decimals);
}
return '-';
}}
maxWidth={300}
/>
<AgGridColumn
headerName={t('Balance')}
field="balance"
-16
View File
@@ -1,16 +0,0 @@
query Asset($assetId: ID!) {
asset(id: $assetId) {
id
name
symbol
decimals
quantum
source {
... on ERC20 {
contractAddress
lifetimeLimit
withdrawThreshold
}
}
}
}
+16 -13
View File
@@ -1,19 +1,22 @@
query AssetsConnection {
fragment AssetsFields on Asset {
id
name
symbol
decimals
quantum
status
source {
... on ERC20 {
contractAddress
}
}
}
query Assets {
assetsConnection {
edges {
node {
id
name
symbol
decimals
quantum
source {
... on ERC20 {
contractAddress
lifetimeLimit
withdrawThreshold
}
}
...AssetsFields
}
}
}
@@ -1,59 +0,0 @@
import { Schema as Types } from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type AssetQueryVariables = Types.Exact<{
assetId: Types.Scalars['ID'];
}>;
export type AssetQuery = { __typename?: 'Query', asset?: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string } } | null };
export const AssetDocument = gql`
query Asset($assetId: ID!) {
asset(id: $assetId) {
id
name
symbol
decimals
quantum
source {
... on ERC20 {
contractAddress
lifetimeLimit
withdrawThreshold
}
}
}
}
`;
/**
* __useAssetQuery__
*
* To run a query within a React component, call `useAssetQuery` and pass it any options that fit your needs.
* When your component renders, `useAssetQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useAssetQuery({
* variables: {
* assetId: // value for 'assetId'
* },
* });
*/
export function useAssetQuery(baseOptions: Apollo.QueryHookOptions<AssetQuery, AssetQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<AssetQuery, AssetQueryVariables>(AssetDocument, options);
}
export function useAssetLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AssetQuery, AssetQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<AssetQuery, AssetQueryVariables>(AssetDocument, options);
}
export type AssetQueryHookResult = ReturnType<typeof useAssetQuery>;
export type AssetLazyQueryHookResult = ReturnType<typeof useAssetLazyQuery>;
export type AssetQueryResult = Apollo.QueryResult<AssetQuery, AssetQueryVariables>;
+37 -32
View File
@@ -3,58 +3,63 @@ import { Schema as Types } from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type AssetsConnectionQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type AssetsFieldsFragment = { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string } };
export type AssetsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type AssetsConnectionQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string } } } | null> | null } | null };
export type AssetsQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string } } } | null> | null } | null };
export const AssetsConnectionDocument = gql`
query AssetsConnection {
assetsConnection {
edges {
node {
id
name
symbol
decimals
quantum
source {
... on ERC20 {
contractAddress
lifetimeLimit
withdrawThreshold
}
}
}
export const AssetsFieldsFragmentDoc = gql`
fragment AssetsFields on Asset {
id
name
symbol
decimals
quantum
status
source {
... on ERC20 {
contractAddress
}
}
}
`;
export const AssetsDocument = gql`
query Assets {
assetsConnection {
edges {
node {
...AssetsFields
}
}
}
}
${AssetsFieldsFragmentDoc}`;
/**
* __useAssetsConnectionQuery__
* __useAssetsQuery__
*
* To run a query within a React component, call `useAssetsConnectionQuery` and pass it any options that fit your needs.
* When your component renders, `useAssetsConnectionQuery` returns an object from Apollo Client that contains loading, error, and data properties
* To run a query within a React component, call `useAssetsQuery` and pass it any options that fit your needs.
* When your component renders, `useAssetsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useAssetsConnectionQuery({
* const { data, loading, error } = useAssetsQuery({
* variables: {
* },
* });
*/
export function useAssetsConnectionQuery(baseOptions?: Apollo.QueryHookOptions<AssetsConnectionQuery, AssetsConnectionQueryVariables>) {
export function useAssetsQuery(baseOptions?: Apollo.QueryHookOptions<AssetsQuery, AssetsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<AssetsConnectionQuery, AssetsConnectionQueryVariables>(AssetsConnectionDocument, options);
return Apollo.useQuery<AssetsQuery, AssetsQueryVariables>(AssetsDocument, options);
}
export function useAssetsConnectionLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AssetsConnectionQuery, AssetsConnectionQueryVariables>) {
export function useAssetsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AssetsQuery, AssetsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<AssetsConnectionQuery, AssetsConnectionQueryVariables>(AssetsConnectionDocument, options);
return Apollo.useLazyQuery<AssetsQuery, AssetsQueryVariables>(AssetsDocument, options);
}
export type AssetsConnectionQueryHookResult = ReturnType<typeof useAssetsConnectionQuery>;
export type AssetsConnectionLazyQueryHookResult = ReturnType<typeof useAssetsConnectionLazyQuery>;
export type AssetsConnectionQueryResult = Apollo.QueryResult<AssetsConnectionQuery, AssetsConnectionQueryVariables>;
export type AssetsQueryHookResult = ReturnType<typeof useAssetsQuery>;
export type AssetsLazyQueryHookResult = ReturnType<typeof useAssetsLazyQuery>;
export type AssetsQueryResult = Apollo.QueryResult<AssetsQuery, AssetsQueryVariables>;
@@ -1,7 +1,7 @@
import { MockedProvider } from '@apollo/react-testing';
import { render, screen } from '@testing-library/react';
import { AssetDetailsDialog } from './asset-details-dialog';
import { AssetsConnectionDocument } from './__generated___/Assets';
import { AssetsDocument } from './__generated___/Assets';
const mockedData = {
data: {
@@ -273,7 +273,7 @@ const mockedData = {
const mocks = [
{
request: {
query: AssetsConnectionDocument,
query: AssetsDocument,
variables: {},
},
result: mockedData,
+18 -16
View File
@@ -1,5 +1,9 @@
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
import type { Asset } from '@vegaprotocol/react-helpers';
import {
addDecimalsFormatNumber,
t,
useDataProvider,
} from '@vegaprotocol/react-helpers';
import type { Asset } from './assets-data-provider';
import {
Button,
Dialog,
@@ -9,7 +13,7 @@ import {
Splash,
Tooltip,
} from '@vegaprotocol/ui-toolkit';
import { useAssetsConnectionQuery } from './__generated___/Assets';
import { assetsProvider } from './assets-data-provider';
import type { Schema } from '@vegaprotocol/types';
import create from 'zustand';
@@ -59,12 +63,10 @@ export const AssetDetailsDialog = ({
open,
onChange,
}: AssetDetailsDialogProps) => {
const { data } = useAssetsConnectionQuery();
const { data } = useDataProvider({ dataProvider: assetsProvider });
const symbol =
typeof assetSymbol === 'string' ? assetSymbol : assetSymbol.symbol;
const asset = data?.assetsConnection?.edges?.find(
(e) => e?.node.symbol === symbol
);
const asset = data?.find((a) => a?.symbol === symbol);
let details: AssetDetails = [];
if (asset != null) {
@@ -72,31 +74,31 @@ export const AssetDetailsDialog = ({
{
key: 'name',
label: t('Name'),
value: asset.node.name,
value: asset.name,
tooltip: '', // t('Name of the asset (e.g: Great British Pound)')
},
{
key: 'symbol',
label: t('Symbol'),
value: asset.node.symbol,
value: asset.symbol,
tooltip: '', // t('Symbol of the asset (e.g: GBP)')
},
{
key: 'decimals',
label: t('Decimals'),
value: asset.node.decimals.toString(),
value: asset.decimals.toString(),
tooltip: t('Number of decimal / precision handled by this asset'),
},
{
key: 'quantum',
label: t('Quantum'),
value: asset.node.quantum,
value: asset.quantum,
tooltip: t('The minimum economically meaningful amount in the asset'),
},
{
key: 'contractaddress',
label: t('Contract address'),
value: (asset.node.source as Schema.ERC20).contractAddress,
value: (asset.source as Schema.ERC20).contractAddress,
tooltip: t(
'The address of the contract for the token, on the ethereum network'
),
@@ -105,8 +107,8 @@ export const AssetDetailsDialog = ({
key: 'withdrawalthreshold',
label: t('Withdrawal threshold'),
value: addDecimalsFormatNumber(
(asset.node.source as Schema.ERC20).withdrawThreshold,
asset.node.decimals
(asset.source as Schema.ERC20).withdrawThreshold,
asset.decimals
),
tooltip: t(
'The maximum allowed per withdraw note: this is a temporary measure for restricted mainnet'
@@ -116,8 +118,8 @@ export const AssetDetailsDialog = ({
key: 'lifetimelimit',
label: t('Lifetime limit'),
value: addDecimalsFormatNumber(
(asset.node.source as Schema.ERC20).lifetimeLimit,
asset.node.decimals
(asset.source as Schema.ERC20).lifetimeLimit,
asset.decimals
),
tooltip: t(
'The lifetime limits deposit per address note: this is a temporary measure for restricted mainnet'
@@ -0,0 +1,60 @@
import {
makeDataProvider,
makeDerivedDataProvider,
} from '@vegaprotocol/react-helpers';
import { AssetsDocument } from './__generated___/Assets';
import { AssetStatus } from '@vegaprotocol/types';
import type {
AssetsQuery,
AssetsFieldsFragment,
} from './__generated___/Assets';
export type Asset = AssetsFieldsFragment;
export interface ERC20AssetSource {
__typename: 'ERC20';
contractAddress: string;
}
export interface BuiltinAssetSource {
__typename: 'BuiltinAsset';
}
export type ERC20Asset = Omit<Asset, 'source'> & {
source: ERC20AssetSource;
};
export type BuiltinAsset = Omit<Asset, 'source'> & {
source: BuiltinAssetSource;
};
export const isAssetTypeERC20 = (
asset?: Pick<Asset, 'source'>
): asset is ERC20Asset => {
if (!asset?.source) return false;
return asset.source.__typename === 'ERC20';
};
const getData = (responseData: AssetsQuery) =>
responseData.assetsConnection?.edges
?.filter((e) => Boolean(e?.node))
.map((e) => e?.node as Asset) ?? [];
export const assetsProvider = makeDataProvider<
AssetsQuery,
Asset[] | null,
never,
never
>({
query: AssetsDocument,
getData,
});
export const enabledAssetsProvider = makeDerivedDataProvider<
ReturnType<typeof getData>,
never
>([assetsProvider], ([assets]) =>
(assets as ReturnType<typeof getData>).filter(
(a) => a.status === AssetStatus.STATUS_ENABLED
)
);
+1
View File
@@ -1,2 +1,3 @@
export * from './__generated___/Assets';
export * from './assets-data-provider';
export * from './asset-details-dialog';
+1 -1
View File
@@ -3,7 +3,7 @@
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
"types": ["jest", "node", "@testing-library/jest-dom"]
},
"include": [
"**/*.test.ts",
+2
View File
@@ -12,6 +12,7 @@ import { addVegaWalletReceiveFaucetedAsset } from './lib/commands/vega-wallet-re
import { addVegaWalletImport } from './lib/commands/vega-wallet-import';
import { addContainsExactly } from './lib/commands/contains-exactly';
import { addRestartVegacapsuleNetwork } from './lib/commands/restart-vegacapsule-network';
import { addGetNetworkParameters } from './lib/commands/get-network-parameters';
addGetTestIdcommand();
addSlackCommand();
@@ -25,6 +26,7 @@ addGetAssetInformation();
addVegaWalletImport();
addContainsExactly();
addRestartVegacapsuleNetwork();
addGetNetworkParameters();
export * from './lib/graphql-test-utils';
export type { onMessage } from './lib/commands/mock-gql';
@@ -0,0 +1,33 @@
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Chainable<Subject> {
get_network_parameters(): void;
}
}
}
export function addGetNetworkParameters() {
// @ts-ignore - ignoring Cypress type error which gets resolved when Cypress uses the command
Cypress.Commands.add('get_network_parameters', () => {
const mutation = '{networkParameters {key value}}';
cy.request({
method: 'POST',
url: `http://localhost:3028/query`,
body: {
query: mutation,
},
headers: { 'content-type': 'application/json' },
})
.its('body.data.networkParameters')
.then(function (response) {
// @ts-ignore - ignoring Cypress type error which gets resolved when Cypress uses the command
const object = response.reduce(function (r, e) {
r[e.key] = e.value;
return r;
}, {});
return object;
});
});
}

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