Compare commits

...
Author SHA1 Message Date
+3 9eee4ff8c4 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>
2022-10-10 10:57:18 +01:00
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