diff --git a/.github/workflows/cypress-pr.yml b/.github/workflows/cypress-pr.yml index 856633cd7..cfacf6ef5 100644 --- a/.github/workflows/cypress-pr.yml +++ b/.github/workflows/cypress-pr.yml @@ -50,20 +50,6 @@ jobs: projects=[${projects// /,}] echo PROJECTS=$projects >> $GITHUB_ENV - # Rename required because some of the files contains the colon character (in the dates) - - name: Rename files to allow archive - if: ${{ always() }} - run: | - while read -r file; do - mv "${file}" "$(echo ${file} | sed 's|:|-|g')" - done< <(find /home/runner/.vegacapsule/testnet/logs -type f) - - - uses: actions/upload-artifact@v3 - if: ${{ always() }} - with: - name: logs-${{ matrix.project }} - path: /home/runner/.vegacapsule/testnet/logs - outputs: projects: ${{ env.PROJECTS }} diff --git a/.github/workflows/cypress-run.yml b/.github/workflows/cypress-run.yml index c329bad8d..36696f31b 100644 --- a/.github/workflows/cypress-run.yml +++ b/.github/workflows/cypress-run.yml @@ -82,6 +82,10 @@ jobs: mv "${file}" "$(echo ${file} | sed 's|:|-|g')" done< <(find /home/runner/.vegacapsule/testnet/logs -type f) + - name: Print logs files + if: ${{ always() }} + run: ls -alsh /home/runner/.vegacapsule/testnet/logs/ + - uses: actions/upload-artifact@v3 if: ${{ always() }} with: diff --git a/apps/explorer-e2e/src/integration/network.cy.js b/apps/explorer-e2e/src/integration/network.cy.js index 5afd69d36..cea6b65f9 100644 --- a/apps/explorer-e2e/src/integration/network.cy.js +++ b/apps/explorer-e2e/src/integration/network.cy.js @@ -247,7 +247,7 @@ context('Network parameters page', { tags: '@smoke' }, function () { .and('include', darkThemeSideMenuBackgroundColor); }); - it('should be able to see network parameters - on mobile', function () { + it.skip('should be able to see network parameters - on mobile', function () { cy.common_switch_to_mobile_and_click_toggle(); cy.get(networkParametersNavigation).click(); cy.get_network_parameters().then((network_parameters) => { diff --git a/apps/explorer/src/app/app.tsx b/apps/explorer/src/app/app.tsx index 7621aada8..1d6ad315c 100644 --- a/apps/explorer/src/app/app.tsx +++ b/apps/explorer/src/app/app.tsx @@ -1,18 +1,16 @@ import classnames from 'classnames'; -import { useState, useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; -import { EnvironmentProvider, NetworkLoader } from '@vegaprotocol/environment'; +import { NetworkLoader, useInitializeEnv } from '@vegaprotocol/environment'; import { Nav } from './components/nav'; import { Header } from './components/header'; import { Main } from './components/main'; import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider'; -import type { InMemoryCacheConfig } from '@apollo/client'; import { Footer } from './components/footer/footer'; import { AnnouncementBanner, ExternalLink } from '@vegaprotocol/ui-toolkit'; import { AssetDetailsDialog, useAssetDetailsDialogStore, } from '@vegaprotocol/assets'; +import { DEFAULT_CACHE_CONFIG } from '@vegaprotocol/apollo-client'; const DialogsContainer = () => { const { isOpen, id, trigger, asJson, setOpen } = useAssetDetailsDialogStore(); @@ -28,36 +26,18 @@ const DialogsContainer = () => { }; function App() { - const [menuOpen, setMenuOpen] = useState(false); - - const location = useLocation(); - - useEffect(() => { - setMenuOpen(false); - }, [location]); - - const cacheConfig: InMemoryCacheConfig = { - typePolicies: { - statistics: { - keyFields: false, - }, - }, - }; - const layoutClasses = classnames( 'grid grid-rows-[auto_1fr_auto] grid-cols-[1fr] md:grid-rows-[auto_minmax(700px,_1fr)_auto] md:grid-cols-[300px_1fr]', 'min-h-[100vh] mx-auto my-0', 'border-neutral-700 dark:border-neutral-300 lg:border-l lg:border-r', 'bg-white dark:bg-black', 'antialiased text-black dark:text-white', - { - 'h-[100vh] min-h-auto overflow-hidden': menuOpen, - } + 'overflow-hidden relative' ); return ( - +
Mainnet sim 2 coming in March! @@ -68,8 +48,8 @@ function App() {
-
-
@@ -81,11 +61,8 @@ function App() { } const Wrapper = () => { - return ( - - - - ); + useInitializeEnv(); + return ; }; export default Wrapper; diff --git a/apps/explorer/src/app/components/dialogs/json-viewer-dialog.tsx b/apps/explorer/src/app/components/dialogs/json-viewer-dialog.tsx new file mode 100644 index 000000000..a3c032f4e --- /dev/null +++ b/apps/explorer/src/app/components/dialogs/json-viewer-dialog.tsx @@ -0,0 +1,56 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { + Button, + Dialog, + Icon, + SyntaxHighlighter, +} from '@vegaprotocol/ui-toolkit'; + +type JsonViewerDialogProps = { + title: string; + content: unknown; + open: boolean; + onChange: (isOpen: boolean) => void; + trigger?: HTMLElement; +}; +export const JsonViewerDialog = ({ + title, + content, + open, + onChange, + trigger, +}: JsonViewerDialogProps) => { + return ( + } + open={open} + onChange={(isOpen) => onChange(isOpen)} + onCloseAutoFocus={(e) => { + /** + * This mimics radix's default behaviour that focuses the dialog's + * trigger after closing itself + */ + if (trigger) { + e.preventDefault(); + trigger.focus(); + } + }} + > +
+ +
+
+ +
+
+ ); +}; diff --git a/apps/explorer/src/app/components/footer/footer.tsx b/apps/explorer/src/app/components/footer/footer.tsx index bc038b364..fd361c458 100644 --- a/apps/explorer/src/app/components/footer/footer.tsx +++ b/apps/explorer/src/app/components/footer/footer.tsx @@ -1,39 +1,46 @@ -import { useEnvironment } from '@vegaprotocol/environment'; +import { NodeSwitcherDialog, useEnvironment } from '@vegaprotocol/environment'; import { t } from '@vegaprotocol/react-helpers'; import { Link } from '@vegaprotocol/ui-toolkit'; +import { useState } from 'react'; export const Footer = () => { - const { VEGA_URL, GIT_COMMIT_HASH, GIT_ORIGIN_URL, setNodeSwitcherOpen } = - useEnvironment(); + const { VEGA_URL, GIT_COMMIT_HASH, GIT_ORIGIN_URL } = useEnvironment(); + const [nodeSwitcherOpen, setNodeSwitcherOpen] = useState(false); return ( -
-
-
- {GIT_COMMIT_HASH && ( -

- {t('Version')}:{' '} - - {GIT_COMMIT_HASH} - -

- )} -
+ <> +
+
+
+ {GIT_COMMIT_HASH && ( +

+ {t('Version')}:{' '} + + {GIT_COMMIT_HASH} + +

+ )} +
-
- {VEGA_URL && } - - {t('Change')} - +
+ {VEGA_URL && } + setNodeSwitcherOpen(true)}> + {t('Change')} + +
-
-
+
+ + ); }; diff --git a/apps/explorer/src/app/components/header/header.spec.tsx b/apps/explorer/src/app/components/header/header.spec.tsx index 36c727f5f..b6a1cb184 100644 --- a/apps/explorer/src/app/components/header/header.spec.tsx +++ b/apps/explorer/src/app/components/header/header.spec.tsx @@ -14,7 +14,7 @@ jest.mock('../search', () => ({ const renderComponent = () => ( -
+
); diff --git a/apps/explorer/src/app/components/header/header.tsx b/apps/explorer/src/app/components/header/header.tsx index 4d0b3b1f1..67cc12488 100644 --- a/apps/explorer/src/app/components/header/header.tsx +++ b/apps/explorer/src/app/components/header/header.tsx @@ -4,15 +4,11 @@ import { ThemeSwitcher, Icon } from '@vegaprotocol/ui-toolkit'; import { t } from '@vegaprotocol/react-helpers'; import { Search } from '../search'; import { Routes } from '../../routes/route-names'; -import type { Dispatch, SetStateAction } from 'react'; import { NetworkSwitcher } from '@vegaprotocol/environment'; +import { useNavStore } from '../nav'; -interface ThemeToggleProps { - menuOpen: boolean; - setMenuOpen: Dispatch>; -} - -export const Header = ({ menuOpen, setMenuOpen }: ThemeToggleProps) => { +export const Header = () => { + const [open, toggle] = useNavStore((state) => [state.open, state.toggle]); const headerClasses = classnames( 'md:col-span-2', 'grid grid-rows-2 md:grid-rows-1 grid-cols-[1fr_auto] md:grid-cols-[auto_1fr_auto] items-center', @@ -36,9 +32,9 @@ export const Header = ({ menuOpen, setMenuOpen }: ThemeToggleProps) => { diff --git a/apps/explorer/src/app/components/main/index.tsx b/apps/explorer/src/app/components/main/index.tsx index 15fa742ad..022d5f98c 100644 --- a/apps/explorer/src/app/components/main/index.tsx +++ b/apps/explorer/src/app/components/main/index.tsx @@ -2,7 +2,7 @@ import { AppRouter } from '../../routes'; export const Main = () => { return ( -
+
); diff --git a/apps/explorer/src/app/components/markets/market-details.tsx b/apps/explorer/src/app/components/markets/market-details.tsx new file mode 100644 index 000000000..27fffab12 --- /dev/null +++ b/apps/explorer/src/app/components/markets/market-details.tsx @@ -0,0 +1,246 @@ +import { + addDecimalsFormatNumber, + formatNumberPercentage, + getMarketExpiryDateFormatted, + t, +} from '@vegaprotocol/react-helpers'; +import type { MarketInfoNoCandlesQuery } from '@vegaprotocol/market-info'; +import { MarketInfoTable } from '@vegaprotocol/market-info'; +import pick from 'lodash/pick'; +import { + MarketStateMapping, + MarketTradingModeMapping, +} from '@vegaprotocol/types'; +import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets'; +import { Splash } from '@vegaprotocol/ui-toolkit'; +import BigNumber from 'bignumber.js'; +import { useMemo } from 'react'; +import { Link } from 'react-router-dom'; + +export const MarketDetails = ({ + market, +}: { + market: MarketInfoNoCandlesQuery['market']; +}) => { + const assetSymbol = + market?.tradableInstrument.instrument.product?.settlementAsset.symbol; + const assetId = useMemo( + () => market?.tradableInstrument.instrument.product?.settlementAsset.id, + [market] + ); + const { data: asset } = useAssetDataProvider(assetId ?? ''); + + if (!market) return null; + + const keyDetails = { + ...pick(market, 'decimalPlaces', 'positionDecimalPlaces', 'tradingMode'), + state: MarketStateMapping[market.state], + }; + const assetDecimals = + market.tradableInstrument.instrument.product.settlementAsset.decimals; + + const panels = [ + { + title: t('Key details'), + content: ( + + ), + }, + { + title: t('Instrument'), + content: ( + + ), + }, + { + title: t('Settlement asset'), + content: asset ? ( + + ) : ( + {t('No data')} + ), + }, + { + title: t('Metadata'), + content: ( + { + const [key, value] = tag.split(':'); + return { [key]: value }; + }) + .reduce((acc, curr) => ({ ...acc, ...curr }), {}), + }} + /> + ), + }, + { + title: t('Risk model'), + content: ( + + ), + }, + { + title: t('Risk parameters'), + content: ( + + ), + }, + { + title: t('Risk factors'), + content: ( + + ), + }, + ...(market.priceMonitoringSettings?.parameters?.triggers || []).map( + (trigger, i) => ({ + title: t(`Price monitoring trigger ${i + 1}`), + content: , + }) + ), + ...(market.data?.priceMonitoringBounds || []).map((trigger, i) => ({ + title: t(`Price monitoring bound ${i + 1}`), + content: ( + <> + + + + ), + })), + { + title: t('Liquidity monitoring parameters'), + content: ( + + ), + }, + { + title: t('Liquidity price range'), + content: ( + + ), + }, + { + title: t('Oracle'), + content: ( + + + {t('View settlement data oracle specification')} + + + {t('View termination oracle specification')} + + + ), + }, + ]; + + return ( + <> + {panels.map((p) => ( +
+

{p.title}

+ {p.content} +
+ ))} + + ); +}; diff --git a/apps/explorer/src/app/components/markets/markets-table.tsx b/apps/explorer/src/app/components/markets/markets-table.tsx new file mode 100644 index 000000000..680cbaa61 --- /dev/null +++ b/apps/explorer/src/app/components/markets/markets-table.tsx @@ -0,0 +1,132 @@ +import type { MarketFieldsFragment } from '@vegaprotocol/market-list'; +import { t } from '@vegaprotocol/react-helpers'; +import type { + VegaICellRendererParams, + VegaValueGetterParams, +} from '@vegaprotocol/ui-toolkit'; +import { ButtonLink } from '@vegaprotocol/ui-toolkit'; +import type { AgGridReact } from 'ag-grid-react'; +import { AgGridColumn } from 'ag-grid-react'; +import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit'; +import { useRef, useLayoutEffect } from 'react'; +import { BREAKPOINT_MD } from '../../config/breakpoints'; +import { MarketStateMapping } from '@vegaprotocol/types'; +import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; +import type { RowClickedEvent } from 'ag-grid-community'; +import { Link, useNavigate } from 'react-router-dom'; + +type MarketsTableProps = { + data: MarketFieldsFragment[] | null; +}; +export const MarketsTable = ({ data }: MarketsTableProps) => { + const openAssetDetailsDialog = useAssetDetailsDialogStore( + (state) => state.open + ); + + const navigate = useNavigate(); + + const gridRef = useRef(null); + useLayoutEffect(() => { + const showColumnsOnDesktop = () => { + gridRef.current?.columnApi.setColumnsVisible( + ['id', 'state', 'asset'], + window.innerWidth > BREAKPOINT_MD + ); + }; + window.addEventListener('resize', showColumnsOnDesktop); + return () => { + window.removeEventListener('resize', showColumnsOnDesktop); + }; + }, []); + + return ( + data.id} + overlayNoRowsTemplate={t('This chain has no markets')} + domLayout="autoHeight" + defaultColDef={{ + flex: 1, + resizable: true, + sortable: true, + filter: true, + filterParams: { buttons: ['reset'] }, + autoHeight: true, + }} + suppressCellFocus={true} + onRowClicked={({ data, event }: RowClickedEvent) => { + if ((event?.target as HTMLElement).tagName.toUpperCase() !== 'BUTTON') { + navigate(data.id); + } + }} + > + + + ) => { + return data?.state ? MarketStateMapping[data?.state] : '-'; + }} + /> + ) => + value ? ( + { + openAssetDetailsDialog(value.id, e.target as HTMLElement); + }} + > + {value.symbol} + + ) : ( + '' + ) + } + /> + + ) => + value ? ( + + {t('View details')} + + ) : ( + '' + ) + } + /> + + ); +}; diff --git a/apps/explorer/src/app/components/nav/index.tsx b/apps/explorer/src/app/components/nav/index.tsx index 0b2c88330..38d674589 100644 --- a/apps/explorer/src/app/components/nav/index.tsx +++ b/apps/explorer/src/app/components/nav/index.tsx @@ -1,45 +1 @@ -import { NavLink } from 'react-router-dom'; -import routerConfig from '../../routes/router-config'; -import classnames from 'classnames'; - -interface NavProps { - menuOpen: boolean; -} - -export const Nav = ({ menuOpen }: NavProps) => { - return ( - - ); -}; +export * from './nav'; diff --git a/apps/explorer/src/app/components/nav/nav.tsx b/apps/explorer/src/app/components/nav/nav.tsx new file mode 100644 index 000000000..8b511e9a2 --- /dev/null +++ b/apps/explorer/src/app/components/nav/nav.tsx @@ -0,0 +1,181 @@ +import { NavLink, useLocation } from 'react-router-dom'; +import type { Navigable } from '../../routes/router-config'; +import routerConfig from '../../routes/router-config'; +import classnames from 'classnames'; +import { create } from 'zustand'; +import { + useCallback, + useEffect, + useLayoutEffect, + useMemo, + useRef, +} from 'react'; +import { Icon } from '@vegaprotocol/ui-toolkit'; +import first from 'lodash/first'; +import last from 'lodash/last'; +import { BREAKPOINT_MD } from '../../config/breakpoints'; + +type NavStore = { + open: boolean; + toggle: () => void; + hide: () => void; +}; + +export const useNavStore = create((set, get) => ({ + open: false, + toggle: () => set({ open: !get().open }), + hide: () => set({ open: false }), +})); + +const NavLinks = ({ links }: { links: Navigable[] }) => { + const navLinks = links.map((r) => ( +
  • + + classnames( + 'block mb-2 px-2', + 'text-lg hover:bg-vega-pink dark:hover:bg-vega-yellow hover:text-white dark:hover:text-black', + { + 'bg-vega-pink text-white dark:bg-vega-yellow dark:text-black': + isActive, + } + ) + } + > + {r.text} + +
  • + )); + + return
      {navLinks}
    ; +}; + +export const Nav = () => { + const [open, hide] = useNavStore((state) => [state.open, state.hide]); + const location = useLocation(); + + const navRef = useRef(null); + const btnRef = useRef(null); + + const focusable = useMemo( + () => + navRef.current + ? [ + ...(navRef.current.querySelectorAll( + 'a, button' + ) as NodeListOf), + ] + : [], + // eslint-disable-next-line react-hooks/exhaustive-deps + [navRef.current] // do not remove `navRef.current` from deps + ); + + const closeNav = useCallback(() => { + hide(); + console.log(focusable); + focusable.forEach((fe) => + fe.setAttribute( + 'tabindex', + window.innerWidth > BREAKPOINT_MD ? '0' : '-1' + ) + ); + }, [focusable, hide]); + + // close navigation when location changes + useEffect(() => { + closeNav(); + }, [closeNav, location]); + + useLayoutEffect(() => { + if (open) { + focusable.forEach((fe) => fe.setAttribute('tabindex', '0')); + } + + document.body.style.overflow = open ? 'hidden' : ''; + const offset = + document.querySelector('header')?.getBoundingClientRect().top || 0; + if (navRef.current) { + navRef.current.style.height = `calc(100vh - ${offset}px)`; + } + + // focus current by default + if (navRef.current && open) { + (navRef.current.querySelector('a[aria-current]') as HTMLElement)?.focus(); + } + + const closeOnEsc = (e: KeyboardEvent) => { + if (e.key === 'Escape') { + closeNav(); + } + }; + + // tabbing loop + const focusLast = (e: FocusEvent) => { + e.preventDefault(); + const isNavElement = + e.relatedTarget && navRef.current?.contains(e.relatedTarget as Node); + if (!isNavElement && open) { + last(focusable)?.focus(); + } + }; + const focusFirst = (e: FocusEvent) => { + e.preventDefault(); + const isNavElement = + e.relatedTarget && navRef.current?.contains(e.relatedTarget as Node); + if (!isNavElement && open) { + first(focusable)?.focus(); + } + }; + + const resetOnDesktop = () => { + focusable.forEach((fe) => + fe.setAttribute( + 'tabindex', + window.innerWidth > BREAKPOINT_MD ? '0' : '-1' + ) + ); + }; + + window.addEventListener('resize', resetOnDesktop); + + first(focusable)?.addEventListener('focusout', focusLast); + last(focusable)?.addEventListener('focusout', focusFirst); + + document.addEventListener('keydown', closeOnEsc); + return () => { + window.removeEventListener('resize', resetOnDesktop); + document.removeEventListener('keydown', closeOnEsc); + first(focusable)?.removeEventListener('focusout', focusLast); + last(focusable)?.removeEventListener('focusout', focusFirst); + }; + }, [closeNav, focusable, open]); + + return ( + + ); +}; diff --git a/apps/explorer/src/app/routes/markets/Markets.graphql b/apps/explorer/src/app/routes/markets/Markets.graphql deleted file mode 100644 index 89fd5e170..000000000 --- a/apps/explorer/src/app/routes/markets/Markets.graphql +++ /dev/null @@ -1,140 +0,0 @@ -query ExplorerMarkets { - marketsConnection { - edges { - node { - id - fees { - factors { - makerFee - infrastructureFee - liquidityFee - } - } - tradableInstrument { - instrument { - name - metadata { - tags - } - code - product { - ... on Future { - settlementAsset { - id - name - decimals - globalRewardPoolAccount { - balance - } - } - } - } - } - riskModel { - ... on LogNormalRiskModel { - tau - riskAversionParameter - params { - r - sigma - mu - } - } - ... on SimpleRiskModel { - params { - factorLong - factorShort - } - } - } - marginCalculator { - scalingFactors { - searchLevel - initialMargin - collateralRelease - } - } - } - decimalPlaces - openingAuction { - durationSecs - volume - } - priceMonitoringSettings { - parameters { - triggers { - horizonSecs - probability - auctionExtensionSecs - } - } - } - liquidityMonitoringParameters { - triggeringRatio - targetStakeParameters { - timeWindow - scalingFactor - } - } - tradingMode - state - proposal { - id - } - state - accountsConnection { - edges { - node { - asset { - id - name - } - balance - type - } - } - } - data { - markPrice - bestBidPrice - bestBidVolume - bestOfferPrice - bestOfferVolume - bestStaticBidPrice - bestStaticBidVolume - bestStaticOfferPrice - bestStaticOfferVolume - midPrice - staticMidPrice - timestamp - openInterest - auctionEnd - auctionStart - indicativePrice - indicativeVolume - trigger - extensionTrigger - targetStake - suppliedStake - priceMonitoringBounds { - minValidPrice - maxValidPrice - trigger { - auctionExtensionSecs - probability - } - referencePrice - } - marketValueProxy - liquidityProviderFeeShare { - party { - id - } - equityLikeShare - averageEntryValuation - } - } - } - } - } -} diff --git a/apps/explorer/src/app/routes/markets/__generated__/Markets.ts b/apps/explorer/src/app/routes/markets/__generated__/Markets.ts deleted file mode 100644 index 3ef1a43f3..000000000 --- a/apps/explorer/src/app/routes/markets/__generated__/Markets.ts +++ /dev/null @@ -1,180 +0,0 @@ -import * as Types from '@vegaprotocol/types'; - -import { gql } from '@apollo/client'; -import * as Apollo from '@apollo/client'; -const defaultOptions = {} as const; -export type ExplorerMarketsQueryVariables = Types.Exact<{ [key: string]: never; }>; - - -export type ExplorerMarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, decimalPlaces: number, tradingMode: Types.MarketTradingMode, state: Types.MarketState, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array | null }, product: { __typename?: 'Future', settlementAsset: { __typename?: 'Asset', id: string, name: string, decimals: number, globalRewardPoolAccount?: { __typename?: 'AccountBalance', balance: string } | null } } }, riskModel: { __typename?: 'LogNormalRiskModel', tau: number, riskAversionParameter: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, marginCalculator?: { __typename?: 'MarginCalculator', scalingFactors: { __typename?: 'ScalingFactors', searchLevel: number, initialMargin: number, collateralRelease: number } } | null }, openingAuction: { __typename?: 'AuctionDuration', durationSecs: number, volume: number }, priceMonitoringSettings: { __typename?: 'PriceMonitoringSettings', parameters?: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null } | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, proposal?: { __typename?: 'Proposal', id?: string | null } | null, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', balance: string, type: Types.AccountType, asset: { __typename?: 'Asset', id: string, name: string } } } | null> | null } | null, data?: { __typename?: 'MarketData', markPrice: string, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, midPrice: string, staticMidPrice: string, timestamp: any, openInterest: string, auctionEnd?: string | null, auctionStart?: string | null, indicativePrice: string, indicativeVolume: string, trigger: Types.AuctionTrigger, extensionTrigger: Types.AuctionTrigger, targetStake?: string | null, suppliedStake?: string | null, marketValueProxy: string, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', auctionExtensionSecs: number, probability: number } }> | null, liquidityProviderFeeShare?: Array<{ __typename?: 'LiquidityProviderFeeShare', equityLikeShare: string, averageEntryValuation: string, party: { __typename?: 'Party', id: string } }> | null } | null } }> } | null }; - - -export const ExplorerMarketsDocument = gql` - query ExplorerMarkets { - marketsConnection { - edges { - node { - id - fees { - factors { - makerFee - infrastructureFee - liquidityFee - } - } - tradableInstrument { - instrument { - name - metadata { - tags - } - code - product { - ... on Future { - settlementAsset { - id - name - decimals - globalRewardPoolAccount { - balance - } - } - } - } - } - riskModel { - ... on LogNormalRiskModel { - tau - riskAversionParameter - params { - r - sigma - mu - } - } - ... on SimpleRiskModel { - params { - factorLong - factorShort - } - } - } - marginCalculator { - scalingFactors { - searchLevel - initialMargin - collateralRelease - } - } - } - decimalPlaces - openingAuction { - durationSecs - volume - } - priceMonitoringSettings { - parameters { - triggers { - horizonSecs - probability - auctionExtensionSecs - } - } - } - liquidityMonitoringParameters { - triggeringRatio - targetStakeParameters { - timeWindow - scalingFactor - } - } - tradingMode - state - proposal { - id - } - state - accountsConnection { - edges { - node { - asset { - id - name - } - balance - type - } - } - } - data { - markPrice - bestBidPrice - bestBidVolume - bestOfferPrice - bestOfferVolume - bestStaticBidPrice - bestStaticBidVolume - bestStaticOfferPrice - bestStaticOfferVolume - midPrice - staticMidPrice - timestamp - openInterest - auctionEnd - auctionStart - indicativePrice - indicativeVolume - trigger - extensionTrigger - targetStake - suppliedStake - priceMonitoringBounds { - minValidPrice - maxValidPrice - trigger { - auctionExtensionSecs - probability - } - referencePrice - } - marketValueProxy - liquidityProviderFeeShare { - party { - id - } - equityLikeShare - averageEntryValuation - } - } - } - } - } -} - `; - -/** - * __useExplorerMarketsQuery__ - * - * To run a query within a React component, call `useExplorerMarketsQuery` and pass it any options that fit your needs. - * When your component renders, `useExplorerMarketsQuery` 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 } = useExplorerMarketsQuery({ - * variables: { - * }, - * }); - */ -export function useExplorerMarketsQuery(baseOptions?: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(ExplorerMarketsDocument, options); - } -export function useExplorerMarketsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(ExplorerMarketsDocument, options); - } -export type ExplorerMarketsQueryHookResult = ReturnType; -export type ExplorerMarketsLazyQueryHookResult = ReturnType; -export type ExplorerMarketsQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/explorer/src/app/routes/markets/index.spec.tsx b/apps/explorer/src/app/routes/markets/index.spec.tsx deleted file mode 100644 index 7786261a6..000000000 --- a/apps/explorer/src/app/routes/markets/index.spec.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { MockedProvider } from '@apollo/client/testing'; -import { render } from '@testing-library/react'; -import { MemoryRouter } from 'react-router-dom'; -import Markets from './index'; -import type { MockedResponse } from '@apollo/client/testing'; -import { ExplorerMarketsDocument } from './__generated__/Markets'; - -function renderComponent(mock: MockedResponse[]) { - return ( - - - - - - ); -} - -describe('Markets index', () => { - it('Renders loader when loading', async () => { - const mock = { - request: { - query: ExplorerMarketsDocument, - }, - result: { - data: { - marketsConnection: [], - }, - }, - }; - const res = render(renderComponent([mock])); - expect(await res.findByTestId('loader')).toBeInTheDocument(); - }); - - it('Renders EmptyList when loading completes and there are no results', async () => { - const mock = { - request: { - query: ExplorerMarketsDocument, - }, - result: { - data: { - marketsConnection: [], - }, - }, - }; - const res = render(renderComponent([mock])); - expect(await res.findByTestId('emptylist')).toBeInTheDocument(); - }); -}); diff --git a/apps/explorer/src/app/routes/markets/index.tsx b/apps/explorer/src/app/routes/markets/index.tsx index 3c87feb68..23da6fdc1 100644 --- a/apps/explorer/src/app/routes/markets/index.tsx +++ b/apps/explorer/src/app/routes/markets/index.tsx @@ -1,44 +1,2 @@ -import React from 'react'; -import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit'; -import { RouteTitle } from '../../components/route-title'; -import { SubHeading } from '../../components/sub-heading'; -import { t } from '@vegaprotocol/react-helpers'; -import { useExplorerMarketsQuery } from './__generated__/Markets'; -import { useScrollToLocation } from '../../hooks/scroll-to-location'; -import { useDocumentTitle } from '../../hooks/use-document-title'; -import EmptyList from '../../components/empty-list/empty-list'; - -const Markets = () => { - const { data, loading } = useExplorerMarketsQuery(); - - useScrollToLocation(); - useDocumentTitle(['Markets']); - - const m = data?.marketsConnection?.edges; - - return ( -
    - {t('Markets')} - - {m ? ( - m.map((e) => ( - - - {e.node.tradableInstrument.instrument.name} - - - - )) - ) : loading ? ( - - ) : ( - - )} -
    - ); -}; - -export default Markets; +export * from './markets-page'; +export * from './market-page'; diff --git a/apps/explorer/src/app/routes/markets/market-page.tsx b/apps/explorer/src/app/routes/markets/market-page.tsx new file mode 100644 index 000000000..7c90251e5 --- /dev/null +++ b/apps/explorer/src/app/routes/markets/market-page.tsx @@ -0,0 +1,68 @@ +import { t, useDataProvider } from '@vegaprotocol/react-helpers'; +import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit'; +import { useMemo, useState } from 'react'; +import { useParams } from 'react-router-dom'; +import { MarketDetails } from '../../components/markets/market-details'; +import { RouteTitle } from '../../components/route-title'; +import { useScrollToLocation } from '../../hooks/scroll-to-location'; +import { useDocumentTitle } from '../../hooks/use-document-title'; +import compact from 'lodash/compact'; +import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog'; +import { marketInfoNoCandlesDataProvider } from '@vegaprotocol/market-info'; + +export const MarketPage = () => { + useScrollToLocation(); + + const { marketId } = useParams<{ marketId: string }>(); + + const variables = useMemo( + () => ({ + marketId, + }), + [marketId] + ); + + const { data, loading, error } = useDataProvider({ + dataProvider: marketInfoNoCandlesDataProvider, + skipUpdates: true, + variables, + }); + + useDocumentTitle( + compact([ + 'Market details', + data?.market?.tradableInstrument.instrument.name, + ]) + ); + + const [dialogOpen, setDialogOpen] = useState(false); + + return ( + <> +
    + + {data?.market?.tradableInstrument.instrument.name} + + +
    + +
    + +
    +
    + setDialogOpen(isOpen)} + title={data?.market?.tradableInstrument.instrument.name || ''} + content={data?.market} + /> + + ); +}; diff --git a/apps/explorer/src/app/routes/markets/markets-page.tsx b/apps/explorer/src/app/routes/markets/markets-page.tsx new file mode 100644 index 000000000..04033c957 --- /dev/null +++ b/apps/explorer/src/app/routes/markets/markets-page.tsx @@ -0,0 +1,31 @@ +import { useScrollToLocation } from '../../hooks/scroll-to-location'; +import { useDocumentTitle } from '../../hooks/use-document-title'; +import { marketsProvider } from '@vegaprotocol/market-list'; +import { RouteTitle } from '../../components/route-title'; +import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; +import { t, useDataProvider } from '@vegaprotocol/react-helpers'; +import { MarketsTable } from '../../components/markets/markets-table'; + +export const MarketsPage = () => { + useDocumentTitle(['Markets']); + useScrollToLocation(); + + const { data, loading, error } = useDataProvider({ + dataProvider: marketsProvider, + skipUpdates: true, + }); + + return ( +
    + {t('Markets')} + + + +
    + ); +}; diff --git a/apps/explorer/src/app/routes/router-config.tsx b/apps/explorer/src/app/routes/router-config.tsx index b55b5bdae..aa6fdb1e1 100644 --- a/apps/explorer/src/app/routes/router-config.tsx +++ b/apps/explorer/src/app/routes/router-config.tsx @@ -2,7 +2,6 @@ import { Assets } from './assets'; import BlockPage from './blocks'; import Governance from './governance'; import Home from './home'; -import Markets from './markets'; import OraclePage from './oracles'; import Oracles from './oracles/home'; import { Oracle } from './oracles/id'; @@ -21,8 +20,13 @@ import flags from '../config/flags'; import { t } from '@vegaprotocol/react-helpers'; import { Routes } from './route-names'; import { NetworkParameters } from './network-parameters'; +import type { RouteObject } from 'react-router-dom'; +import { MarketPage, MarketsPage } from './markets'; -const partiesRoutes = flags.parties +export type Navigable = { path: string; name: string; text: string }; +type Route = RouteObject & Navigable; + +const partiesRoutes: Route[] = flags.parties ? [ { path: Routes.PARTIES, @@ -43,7 +47,7 @@ const partiesRoutes = flags.parties ] : []; -const assetsRoutes = flags.assets +const assetsRoutes: Route[] = flags.assets ? [ { path: Routes.ASSETS, @@ -54,7 +58,7 @@ const assetsRoutes = flags.assets ] : []; -const genesisRoutes = flags.genesis +const genesisRoutes: Route[] = flags.genesis ? [ { path: Routes.GENESIS, @@ -65,7 +69,7 @@ const genesisRoutes = flags.genesis ] : []; -const governanceRoutes = flags.governance +const governanceRoutes: Route[] = flags.governance ? [ { path: Routes.GOVERNANCE, @@ -76,18 +80,27 @@ const governanceRoutes = flags.governance ] : []; -const marketsRoutes = flags.markets +const marketsRoutes: Route[] = flags.markets ? [ { path: Routes.MARKETS, name: 'Markets', text: t('Markets'), - element: , + children: [ + { + index: true, + element: , + }, + { + path: ':marketId', + element: , + }, + ], }, ] : []; -const networkParametersRoutes = flags.networkParameters +const networkParametersRoutes: Route[] = flags.networkParameters ? [ { path: Routes.NETWORK_PARAMETERS, @@ -97,7 +110,7 @@ const networkParametersRoutes = flags.networkParameters }, ] : []; -const validators = flags.validators +const validators: Route[] = flags.validators ? [ { path: Routes.VALIDATORS, @@ -108,7 +121,7 @@ const validators = flags.validators ] : []; -const routerConfig = [ +const routerConfig: Route[] = [ { path: Routes.HOME, name: 'Home', diff --git a/apps/liquidity-provision-dashboard/src/app/app.tsx b/apps/liquidity-provision-dashboard/src/app/app.tsx index 757b88c0f..357d05186 100644 --- a/apps/liquidity-provision-dashboard/src/app/app.tsx +++ b/apps/liquidity-provision-dashboard/src/app/app.tsx @@ -1,3 +1,5 @@ +import type { InMemoryCacheConfig } from '@apollo/client'; +import { NetworkLoader, useInitializeEnv } from '@vegaprotocol/environment'; import { useRoutes } from 'react-router-dom'; import '../styles.scss'; @@ -5,14 +7,40 @@ import { Navbar } from './components/navbar'; import { routerConfig } from './routes/router-config'; +const cache: InMemoryCacheConfig = { + typePolicies: { + Market: { + merge: true, + }, + Party: { + merge: true, + }, + Query: {}, + Account: { + keyFields: false, + fields: { + balanceFormatted: {}, + }, + }, + Node: { + keyFields: false, + }, + Instrument: { + keyFields: false, + }, + }, +}; const AppRouter = () => useRoutes(routerConfig); export function App() { + useInitializeEnv(); return ( -
    - - -
    + +
    + + +
    +
    ); } diff --git a/apps/liquidity-provision-dashboard/src/main.tsx b/apps/liquidity-provision-dashboard/src/main.tsx index addcc9921..7615e405e 100644 --- a/apps/liquidity-provision-dashboard/src/main.tsx +++ b/apps/liquidity-provision-dashboard/src/main.tsx @@ -1,44 +1,15 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; -import { EnvironmentProvider, NetworkLoader } from '@vegaprotocol/environment'; import App from './app/app'; -import type { InMemoryCacheConfig } from '@apollo/client'; const rootElement = document.getElementById('root'); const root = rootElement && createRoot(rootElement); -const cache: InMemoryCacheConfig = { - typePolicies: { - Market: { - merge: true, - }, - Party: { - merge: true, - }, - Query: {}, - Account: { - keyFields: false, - fields: { - balanceFormatted: {}, - }, - }, - Node: { - keyFields: false, - }, - Instrument: { - keyFields: false, - }, - }, -}; root?.render( - - - - - + ); diff --git a/apps/multisig-signer/.env b/apps/multisig-signer/.env index 02483fefb..ddb4546bd 100644 --- a/apps/multisig-signer/.env +++ b/apps/multisig-signer/.env @@ -2,3 +2,4 @@ NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json NX_VEGA_NETWORKS='{"TESTNET":"https://multisig-signer.fairground.wtf","MAINNET":"https://multisig-signer.vega.xyz"}' NX_VEGA_ENV=STAGNET3 + diff --git a/apps/multisig-signer/src/app/app.tsx b/apps/multisig-signer/src/app/app.tsx index f20c6abbe..4707f6f50 100644 --- a/apps/multisig-signer/src/app/app.tsx +++ b/apps/multisig-signer/src/app/app.tsx @@ -3,9 +3,9 @@ import classnames from 'classnames'; import { useEffect, useMemo, useState } from 'react'; import { BrowserTracing } from '@sentry/tracing'; import { - EnvironmentProvider, NetworkLoader, useEnvironment, + useInitializeEnv, } from '@vegaprotocol/environment'; import { AsyncRenderer, Button, Lozenge } from '@vegaprotocol/ui-toolkit'; import type { EthereumConfig } from '@vegaprotocol/web3'; @@ -64,6 +64,7 @@ function App() { environment: VEGA_ENV, }); }, [VEGA_ENV]); + const Connectors = useMemo(() => { if (config?.chain_id) { return createConnectors(ETHEREUM_PROVIDER_URL, Number(config.chain_id)); @@ -107,12 +108,11 @@ const Wrapper = () => { }, }, }; + useInitializeEnv(); return ( - - - - - + + + ); }; diff --git a/apps/static/src/assets/mainnet-tranches.json b/apps/static/src/assets/mainnet-tranches.json index bf761c394..8719c664c 100644 --- a/apps/static/src/assets/mainnet-tranches.json +++ b/apps/static/src/assets/mainnet-tranches.json @@ -2761,7 +2761,7 @@ "tranche_end": "2023-12-05T00:00:00.000Z", "total_added": "86666.297", "total_removed": "0", - "locked_amount": "69688.1039444538563298071", + "locked_amount": "68975.3330121062666493861", "deposits": [ { "amount": "86666.297", @@ -2827,7 +2827,7 @@ "tranche_end": "2023-06-01T00:00:00.000Z", "total_added": "2500", "total_removed": "0", - "locked_amount": "1462.84865308302825", + "locked_amount": "1421.61410637973125", "deposits": [ { "amount": "2500", @@ -3214,8 +3214,8 @@ "tranche_start": "2023-02-01T00:00:00.000Z", "tranche_end": "2023-08-01T00:00:00.000Z", "total_added": "37500", - "total_removed": "470.314897875", - "locked_amount": "34702.08189456721875", + "total_removed": "2836.415649675", + "locked_amount": "34080.14646639042375", "deposits": [ { "amount": "7500", @@ -3234,6 +3234,16 @@ "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", "tx": "0x7b40703e0fb0e1da154999d5d022df7b5dec42d14d9ff75298233227da2770c5" }, + { + "amount": "90.9875691", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0x5bfef799be13741d89872cc604df1f35b41069397e681577fc15c039866d8707" + }, + { + "amount": "2275.1131827", + "user": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600", + "tx": "0x78fd0cf1ca8de93d15eee1424146bcd70b84cc168b4c1ea1ac50020b8d67bcc1" + }, { "amount": "183.137181525", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -3263,6 +3273,12 @@ "tranche_id": 34, "tx": "0x7b40703e0fb0e1da154999d5d022df7b5dec42d14d9ff75298233227da2770c5" }, + { + "amount": "90.9875691", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 34, + "tx": "0x5bfef799be13741d89872cc604df1f35b41069397e681577fc15c039866d8707" + }, { "amount": "183.137181525", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -3277,8 +3293,8 @@ } ], "total_tokens": "7500", - "withdrawn_tokens": "470.314897875", - "remaining_tokens": "7029.685102125" + "withdrawn_tokens": "561.302466975", + "remaining_tokens": "6938.697533025" }, { "address": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600", @@ -3290,10 +3306,17 @@ "tx": "0x302591debd812f93121a17dd0413ae5084f3743a868b4325f81990eac58f8292" } ], - "withdrawals": [], + "withdrawals": [ + { + "amount": "2275.1131827", + "user": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600", + "tranche_id": 34, + "tx": "0x78fd0cf1ca8de93d15eee1424146bcd70b84cc168b4c1ea1ac50020b8d67bcc1" + } + ], "total_tokens": "30000", - "withdrawn_tokens": "0", - "remaining_tokens": "30000" + "withdrawn_tokens": "2275.1131827", + "remaining_tokens": "27724.8868173" } ] }, @@ -3303,7 +3326,7 @@ "tranche_end": "2023-12-05T00:00:00.000Z", "total_added": "129999.45", "total_removed": "0", - "locked_amount": "69624.522318098021561175", + "locked_amount": "68912.401699541887736445", "deposits": [ { "amount": "129999.45", @@ -3369,7 +3392,7 @@ "tranche_end": "2023-09-03T00:00:00.000Z", "total_added": "62600", "total_removed": "0", - "locked_amount": "34386.33125951293992", + "locked_amount": "33871.4891362252656", "deposits": [ { "amount": "10000", @@ -3562,7 +3585,7 @@ "tranche_end": "2023-09-17T00:00:00.000Z", "total_added": "5000", "total_removed": "0", - "locked_amount": "2938.292903348554", + "locked_amount": "2897.1713280060885", "deposits": [ { "amount": "5000", @@ -3773,7 +3796,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "97499.58", "total_removed": "0", - "locked_amount": "11517.3721993387044218526", + "locked_amount": "10818.8482095714036717828", "deposits": [ { "amount": "97499.58", @@ -3806,7 +3829,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "135173.4239508", "total_removed": "98230.390980249184455396", - "locked_amount": "15742.259405136849384682186284", + "locked_amount": "14787.49770626082669661645614", "deposits": [ { "amount": "135173.4239508", @@ -3852,7 +3875,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "32499.86", "total_removed": "0", - "locked_amount": "4845.1595898824455710212", + "locked_amount": "4551.302610251424035468", "deposits": [ { "amount": "32499.86", @@ -3885,7 +3908,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "10833.29", "total_removed": "0", - "locked_amount": "1577.052430190972462962", + "locked_amount": "1481.4048348417078526675", "deposits": [ { "amount": "10833.29", @@ -3918,7 +3941,7 @@ "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "22749.93", "total_removed": "4720.860935375", - "locked_amount": "5895.374212352749174155", + "locked_amount": "5537.8221384325917571011", "deposits": [ { "amount": "6500", @@ -4069,8 +4092,8 @@ "tranche_start": "2022-11-01T00:00:00.000Z", "tranche_end": "2023-05-01T00:00:00.000Z", "total_added": "22500", - "total_removed": "4282.463838975", - "locked_amount": "9384.785048342541375", + "total_removed": "4373.451408", + "locked_amount": "9011.6237914364655", "deposits": [ { "amount": "7500", @@ -4089,6 +4112,11 @@ "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", "tx": "0xf121e9810d454c5814a73b5b58e28c026bc53246bad6f6ba7836fb9e0adbd12a" }, + { + "amount": "90.987569025", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0x4a7c7462e3bb6abe2d33dfe5a1bf1e4211e52e5e03239c02554988f7d3635523" + }, { "amount": "167.6680479", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -4178,6 +4206,12 @@ "tranche_id": 33, "tx": "0xf121e9810d454c5814a73b5b58e28c026bc53246bad6f6ba7836fb9e0adbd12a" }, + { + "amount": "90.987569025", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 33, + "tx": "0x4a7c7462e3bb6abe2d33dfe5a1bf1e4211e52e5e03239c02554988f7d3635523" + }, { "amount": "167.6680479", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -4264,8 +4298,8 @@ } ], "total_tokens": "7500", - "withdrawn_tokens": "4282.463838975", - "remaining_tokens": "3217.536161025" + "withdrawn_tokens": "4373.451408", + "remaining_tokens": "3126.548592" }, { "address": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1", @@ -4290,7 +4324,7 @@ "tranche_end": "2023-06-02T00:00:00.000Z", "total_added": "1939928.38", "total_removed": "928642.9598472029154", - "locked_amount": "571324.225076622795836682", + "locked_amount": "555369.642869191387312504", "deposits": [ { "amount": "1852091.69", @@ -7264,10 +7298,15 @@ "tranche_id": 10, "tranche_start": "2021-07-15T23:37:11.000Z", "tranche_end": "2021-07-15T23:37:11.000Z", - "total_added": "6159302.299000000000000001", - "total_removed": "6113483.280000000000000001", + "total_added": "6259302.299000000000000001", + "total_removed": "6213483.280000000000000001", "locked_amount": "0", "deposits": [ + { + "amount": "100000", + "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", + "tx": "0xa4417547c32fb4936e0dd6ee338ba31b2fd622388fe8a3906d9e7020d5e8371b" + }, { "amount": "100000", "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", @@ -7790,6 +7829,11 @@ } ], "withdrawals": [ + { + "amount": "100000", + "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", + "tx": "0xa4417547c32fb4936e0dd6ee338ba31b2fd622388fe8a3906d9e7020d5e8371b" + }, { "amount": "100000", "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", @@ -8255,6 +8299,12 @@ { "address": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", "deposits": [ + { + "amount": "100000", + "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", + "tranche_id": 10, + "tx": "0xa4417547c32fb4936e0dd6ee338ba31b2fd622388fe8a3906d9e7020d5e8371b" + }, { "amount": "100000", "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", @@ -8437,6 +8487,12 @@ } ], "withdrawals": [ + { + "amount": "100000", + "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", + "tranche_id": 10, + "tx": "0xa4417547c32fb4936e0dd6ee338ba31b2fd622388fe8a3906d9e7020d5e8371b" + }, { "amount": "100000", "user": "0xb2d6DEC77558Cf8EdB7c428d23E70Eab0688544f", @@ -8612,8 +8668,8 @@ "tx": "0xac16a4ce688d40a482a59914d68c3a676592f8804ee8f0781b66a4ba5ccfbdfc" } ], - "total_tokens": "2956651", - "withdrawn_tokens": "2956651", + "total_tokens": "3056651", + "withdrawn_tokens": "3056651", "remaining_tokens": "0" }, { @@ -36560,7 +36616,7 @@ "tranche_end": "2023-06-05T00:00:00.000Z", "total_added": "3732368.4671", "total_removed": "592998.0503546212334", - "locked_amount": "902427.744703753194520599278", + "locked_amount": "877911.01211975962832293262", "deposits": [ { "amount": "1998.95815", @@ -37885,8 +37941,8 @@ "tranche_start": "2022-06-05T00:00:00.000Z", "tranche_end": "2023-12-05T00:00:00.000Z", "total_added": "15870102.715470999700000001", - "total_removed": "565200.35868260229965452", - "locked_amount": "8499638.4269611804875989817529270644971615", + "total_removed": "570447.40018226362274952", + "locked_amount": "8412703.667343023478982687330398519288997", "deposits": [ { "amount": "16249.93", @@ -38405,6 +38461,26 @@ "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", "tx": "0x3d26957f37b25306381e1cd2f6d9efea7ec698e837c4b2bda76ca2e2ef8028ba" }, + { + "amount": "276.3015353431795", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0x71e874dd2277e6c5838399943e59bae3b006a06505fb3eacb81a4a6b6bf51a0b" + }, + { + "amount": "509.243563215814625", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tx": "0x307e498402679f0f8ee11dcd3dfc684db5558203469f07ce58e98a4f87f0fa62" + }, + { + "amount": "1640.93679110232897", + "user": "0xe3eB4CF43C072658401996b71D43eE26E573562D", + "tx": "0x4870598253a2a664d9c96af37904f08ac772ee9620b5975560ef7e7fb51c9a7f" + }, + { + "amount": "2820.55961", + "user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37", + "tx": "0x039c7d1eb6b18a13c3fb91589403d43710e12b319e7d40936280a576502f80fe" + }, { "amount": "856.08784586478614", "user": "0xe3eB4CF43C072658401996b71D43eE26E573562D", @@ -40101,6 +40177,18 @@ "tranche_id": 2, "tx": "0x3d26957f37b25306381e1cd2f6d9efea7ec698e837c4b2bda76ca2e2ef8028ba" }, + { + "amount": "276.3015353431795", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0x71e874dd2277e6c5838399943e59bae3b006a06505fb3eacb81a4a6b6bf51a0b" + }, + { + "amount": "509.243563215814625", + "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", + "tranche_id": 2, + "tx": "0x307e498402679f0f8ee11dcd3dfc684db5558203469f07ce58e98a4f87f0fa62" + }, { "amount": "966.75883976995675", "user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b", @@ -41243,8 +41331,8 @@ } ], "total_tokens": "259998.8875", - "withdrawn_tokens": "120493.09714116867225", - "remaining_tokens": "139505.79035883132775" + "withdrawn_tokens": "121278.642239727666375", + "remaining_tokens": "138720.245260272333625" }, { "address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c", @@ -41465,6 +41553,12 @@ } ], "withdrawals": [ + { + "amount": "1640.93679110232897", + "user": "0xe3eB4CF43C072658401996b71D43eE26E573562D", + "tranche_id": 2, + "tx": "0x4870598253a2a664d9c96af37904f08ac772ee9620b5975560ef7e7fb51c9a7f" + }, { "amount": "856.08784586478614", "user": "0xe3eB4CF43C072658401996b71D43eE26E573562D", @@ -41695,8 +41789,8 @@ } ], "total_tokens": "150551.801", - "withdrawn_tokens": "68648.27553278775093", - "remaining_tokens": "81903.52546721224907" + "withdrawn_tokens": "70289.2123238900799", + "remaining_tokens": "80262.5886761099201" }, { "address": "0x4d982Ab0823fD2f48e934a7be2bb0a5374a26148", @@ -41898,6 +41992,12 @@ } ], "withdrawals": [ + { + "amount": "2820.55961", + "user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37", + "tranche_id": 2, + "tx": "0x039c7d1eb6b18a13c3fb91589403d43710e12b319e7d40936280a576502f80fe" + }, { "amount": "1412.763584", "user": "0xF4c75FdbAe821C6B5DBB9f001bB23cBA58D1bA37", @@ -42098,8 +42198,8 @@ } ], "total_tokens": "200000", - "withdrawn_tokens": "90814.016456", - "remaining_tokens": "109185.983544" + "withdrawn_tokens": "93634.576066", + "remaining_tokens": "106365.423934" }, { "address": "0x1b956E6c00E238194B331eddEFF72Cb5f28A8d01", @@ -43451,8 +43551,8 @@ "tranche_start": "2021-11-05T00:00:00.000Z", "tranche_end": "2023-05-05T00:00:00.000Z", "total_added": "14597706.0446472999", - "total_removed": "3925878.714389493431486282", - "locked_amount": "2125366.69877648768310833917076124", + "total_removed": "3926967.723059737571037032", + "locked_amount": "2045109.08378068825804623195557898", "deposits": [ { "amount": "129284.449", @@ -43676,6 +43776,16 @@ "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", "tx": "0xddcbb09fcdd4093749d76f4d5f882339989f87089ebe36ac64c4243b6f09b976" }, + { + "amount": "383.4048631759663005", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0xf1c4c72d4c71eb26378b943efeafb5c1607a79d5163a2c8ae8c4ddce2afaf7ad" + }, + { + "amount": "705.60380706817325025", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tx": "0x532c270b8a50b8e2923a96b038129a203e01eba1b84faf238dd9b48aeceb1c91" + }, { "amount": "1333.9237119810715295", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -46560,6 +46670,18 @@ "tranche_id": 3, "tx": "0xddcbb09fcdd4093749d76f4d5f882339989f87089ebe36ac64c4243b6f09b976" }, + { + "amount": "383.4048631759663005", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0xf1c4c72d4c71eb26378b943efeafb5c1607a79d5163a2c8ae8c4ddce2afaf7ad" + }, + { + "amount": "705.60380706817325025", + "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", + "tranche_id": 3, + "tx": "0x532c270b8a50b8e2923a96b038129a203e01eba1b84faf238dd9b48aeceb1c91" + }, { "amount": "1333.9237119810715295", "user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b", @@ -49004,8 +49126,8 @@ } ], "total_tokens": "359123.469575", - "withdrawn_tokens": "306480.52161894473088575", - "remaining_tokens": "52642.94795605526911425" + "withdrawn_tokens": "307569.5302891888704365", + "remaining_tokens": "51553.9392858111295635" }, { "address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB", @@ -50342,8 +50464,8 @@ "tranche_start": "2021-10-05T00:00:00.000Z", "tranche_end": "2023-04-05T00:00:00.000Z", "total_added": "5778205.3912159303", - "total_removed": "2731059.487268130842706642", - "locked_amount": "522841.833257185626759758659733921", + "total_removed": "2749067.463242913023296295", + "locked_amount": "491131.564178330845541202121121822", "deposits": [ { "amount": "552496.6455", @@ -50492,6 +50614,21 @@ "user": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75", "tx": "0x33da947571f71b4cd31f2cfc13cbcceba0bac110b7a975a4793afe40566d3741" }, + { + "amount": "4961.957448767374506", + "user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90", + "tx": "0x5ee84120105b5caa7e2d12e10bb2aeb234fcfaa416203d8b2b2fe68c06ed535e" + }, + { + "amount": "10871.612867264090097103", + "user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d", + "tx": "0xf39eb46d1f973f6a0bb31a553dc087fa94933994d18b1e46a630490c2b7cbb04" + }, + { + "amount": "2174.40565875071598655", + "user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D", + "tx": "0xb49529fae65600b960a8a6cebd02a4c8480983d0f399a14167b14462583cac47" + }, { "amount": "19117.297184565582142", "user": "0x1dD2718fd01d05C9F50Fce8Bb723A4C7483A1E15", @@ -51563,6 +51700,12 @@ } ], "withdrawals": [ + { + "amount": "2174.40565875071598655", + "user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D", + "tranche_id": 4, + "tx": "0xb49529fae65600b960a8a6cebd02a4c8480983d0f399a14167b14462583cac47" + }, { "amount": "3751.78499041934834165", "user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D", @@ -51649,8 +51792,8 @@ } ], "total_tokens": "92082.572555", - "withdrawn_tokens": "81632.04967906306698935", - "remaining_tokens": "10450.52287593693301065" + "withdrawn_tokens": "83806.4553378137829759", + "remaining_tokens": "8276.1172171862170241" }, { "address": "0x1dC9B91DE003fd503F25cB5d114cf0fc68F7aFe6", @@ -51678,6 +51821,12 @@ } ], "withdrawals": [ + { + "amount": "10871.612867264090097103", + "user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d", + "tranche_id": 4, + "tx": "0xf39eb46d1f973f6a0bb31a553dc087fa94933994d18b1e46a630490c2b7cbb04" + }, { "amount": "18757.845956872719119701", "user": "0xC24da173A250e9Ca5c54870639EbE5f88be5102d", @@ -51788,8 +51937,8 @@ } ], "total_tokens": "460415.072915097", - "withdrawn_tokens": "408161.740088926747515886", - "remaining_tokens": "52253.332826170252484114" + "withdrawn_tokens": "419033.352956190837612989", + "remaining_tokens": "41381.719958906162387011" }, { "address": "0xd66e4853c0880df150e7329974715BFC8d2da47D", @@ -51998,6 +52147,12 @@ } ], "withdrawals": [ + { + "amount": "4961.957448767374506", + "user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90", + "tranche_id": 4, + "tx": "0x5ee84120105b5caa7e2d12e10bb2aeb234fcfaa416203d8b2b2fe68c06ed535e" + }, { "amount": "4217.129347329502683", "user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90", @@ -52240,8 +52395,8 @@ } ], "total_tokens": "331498.5873", - "withdrawn_tokens": "296737.775114654365887", - "remaining_tokens": "34760.812185345634113" + "withdrawn_tokens": "301699.732563421740393", + "remaining_tokens": "29798.854736578259607" }, { "address": "0x16da609341ed67750A8BCC5AAa2005471006Cd77", @@ -52336,8 +52491,8 @@ "tranche_start": "2022-06-05T00:00:00.000Z", "tranche_end": "2023-06-05T00:00:00.000Z", "total_added": "472355.6199999996", - "total_removed": "33576.5289478972685", - "locked_amount": "142994.834645218686769341671841696", + "total_removed": "33662.0369387672685", + "locked_amount": "139110.018223666781876256383155776", "deposits": [ { "amount": "3000", @@ -59011,6 +59166,21 @@ "user": "0xb1EAD214506D0cD73785Dd09B3EfC2307133bf69", "tx": "0x6b3f814e3018e59a0557e5e377ee2b8962db59171fe3bff57e887f58f732c1b5" }, + { + "amount": "48.073439878", + "user": "0xC91A06E92bFc696BCcFcDd564F376beDC40932cF", + "tx": "0x20750a137fa15fd06a1c7b0a40226fd2f78310bba9b2246b1b4ab23db72e5177" + }, + { + "amount": "19.035312024", + "user": "0x4F4A140E9B4a8403792970C6b5535ed0AA32c8A4", + "tx": "0x181a9afe9b3592427f1ee10f205e01f34ae7be383294e8d93e397766092bf6df" + }, + { + "amount": "18.399238968", + "user": "0xD3ec605d078326B0a636ca90d496Ebb5Eb457a27", + "tx": "0xa82e451753cbced76b064af62868d3170dff7afca557680e657c27ebba5c7beb" + }, { "amount": "13.1116203702", "user": "0x4cBC0C88d8FE503f62823B42f30a4900292C13bE", @@ -67169,6 +67339,12 @@ } ], "withdrawals": [ + { + "amount": "18.399238968", + "user": "0xD3ec605d078326B0a636ca90d496Ebb5Eb457a27", + "tranche_id": 5, + "tx": "0xa82e451753cbced76b064af62868d3170dff7afca557680e657c27ebba5c7beb" + }, { "amount": "262.76406646", "user": "0xD3ec605d078326B0a636ca90d496Ebb5Eb457a27", @@ -67177,8 +67353,8 @@ } ], "total_tokens": "400", - "withdrawn_tokens": "262.76406646", - "remaining_tokens": "137.23593354" + "withdrawn_tokens": "281.163305428", + "remaining_tokens": "118.836694572" }, { "address": "0x7f6aba7563Cb5d31980D440337D3d1A6e3dB58F3", @@ -75018,6 +75194,12 @@ } ], "withdrawals": [ + { + "amount": "48.073439878", + "user": "0xC91A06E92bFc696BCcFcDd564F376beDC40932cF", + "tranche_id": 5, + "tx": "0x20750a137fa15fd06a1c7b0a40226fd2f78310bba9b2246b1b4ab23db72e5177" + }, { "amount": "91.388045408", "user": "0xC91A06E92bFc696BCcFcDd564F376beDC40932cF", @@ -75026,8 +75208,8 @@ } ], "total_tokens": "200", - "withdrawn_tokens": "91.388045408", - "remaining_tokens": "108.611954592" + "withdrawn_tokens": "139.461485286", + "remaining_tokens": "60.538514714" }, { "address": "0xca680a0524F1440bA14afA3d6A57D73bBA7E138d", @@ -75284,6 +75466,12 @@ } ], "withdrawals": [ + { + "amount": "19.035312024", + "user": "0x4F4A140E9B4a8403792970C6b5535ed0AA32c8A4", + "tranche_id": 5, + "tx": "0x181a9afe9b3592427f1ee10f205e01f34ae7be383294e8d93e397766092bf6df" + }, { "amount": "19.78325723", "user": "0x4F4A140E9B4a8403792970C6b5535ed0AA32c8A4", @@ -75310,8 +75498,8 @@ } ], "total_tokens": "200", - "withdrawn_tokens": "120.858288938", - "remaining_tokens": "79.141711062" + "withdrawn_tokens": "139.893600962", + "remaining_tokens": "60.106399038" }, { "address": "0x4DA5acEc788beF3d7F67cEA1c3CfeE1a41c1A21A", diff --git a/apps/token-e2e/src/integration/flow/governance-enacted-flow.cy.js b/apps/token-e2e/src/integration/flow/governance-enacted-flow.cy.js new file mode 100644 index 000000000..a875d2b2b --- /dev/null +++ b/apps/token-e2e/src/integration/flow/governance-enacted-flow.cy.js @@ -0,0 +1,143 @@ +/// + +import { + createUpdateNetworkProposalTxBody, + createFreeFormProposalTxBody, +} from '../../support/proposal.functions'; + +const closedProposals = '[data-testid="closed-proposals"]'; +const proposalStatus = '[data-testid="proposal-status"]'; +const viewProposalButton = '[data-testid="view-proposal-btn"]'; +const votesTable = '[data-testid="votes-table"]'; +const openProposals = '[data-testid="open-proposals"]'; +const proposalVoteProgressForPercentage = + '[data-testid="vote-progress-indicator-percentage-for"]'; +const proposalTimeout = { timeout: 8000 }; + +context( + 'Proposal flow - with proposals enacted or failed', + { tags: '@slow' }, + function () { + before('Connect wallets and set approval', function () { + cy.visit('/'); + cy.vega_wallet_set_specified_approval_amount('1000'); + cy.connectVegaWallet(); + cy.ethereum_wallet_connect(); + cy.ensure_specified_unstaked_tokens_are_associated(1); + cy.clearLocalStorage(); + }); + + beforeEach('visit proposals', function () { + cy.reload(); + cy.wait_for_spinner(); + cy.connectVegaWallet(); + cy.ethereum_wallet_connect(); + cy.navigate_to('proposals'); + }); + + // 3001-VOTE-006 + it('Able to view enacted proposal', function () { + const proposalTitle = 'Add Lorem Ipsum market'; + + cy.createMarket(); + cy.reload(); + cy.wait_for_spinner(); + cy.get(closedProposals).within(() => { + cy.contains(proposalTitle) + .parentsUntil('[data-testid="proposals-list-item"]') + .within(() => { + cy.get(proposalStatus).should('have.text', 'Enacted '); + cy.get(viewProposalButton).click(); + }); + }); + cy.getByTestId('proposal-type').should('have.text', 'New market'); + cy.get_proposal_information_from_table('State') + .contains('Enacted') + .and('be.visible'); + cy.get(votesTable).within(() => { + cy.contains('Vote passed.').should('be.visible'); + cy.contains('Voting has ended.').should('be.visible'); + }); + }); + + // 3001-VOTE-046 3001-VOTE-044 3001-VOTE-074 3001-VOTE-074 + it('Able to enact proposal by voting', function () { + const proposalTitle = 'Add New proposal with short enactment'; + const proposalTx = createUpdateNetworkProposalTxBody(); + + cy.VegaWalletSubmitProposal(proposalTx); + cy.navigate_to('proposals'); + cy.reload(); + cy.wait_for_spinner(); + cy.get(openProposals).within(() => { + cy.contains(proposalTitle) + .parentsUntil('[data-testid="proposals-list-item"]') + .within(() => cy.get(viewProposalButton).click()); + }); + cy.get_proposal_information_from_table('State') + .contains('Open') + .and('be.visible'); + cy.vote_for_proposal('for'); + cy.get_proposal_information_from_table('State') // 3001-VOTE-047 + .contains('Passed', proposalTimeout) + .and('be.visible'); + cy.get_proposal_information_from_table('State') + .contains('Enacted', proposalTimeout) + .and('be.visible'); + cy.get(votesTable).within(() => { + cy.contains('Vote passed.').should('be.visible'); + cy.contains('Voting has ended.').should('be.visible'); + }); + cy.get(proposalVoteProgressForPercentage) + .contains('100.00%') + .and('be.visible'); + }); + + // 3001-VOTE-047 + it('Able to enact freeform proposal', function () { + const proposalTitle = 'Add New free form proposal with short enactment'; + const proposalTx = createFreeFormProposalTxBody(); + + cy.VegaWalletSubmitProposal(proposalTx); + cy.navigate_to('proposals'); + cy.reload(); + cy.wait_for_spinner(); + cy.get(openProposals).within(() => { + cy.contains(proposalTitle) + .parentsUntil('[data-testid="proposals-list-item"]') + .within(() => cy.get(viewProposalButton).click()); + }); + cy.get_proposal_information_from_table('State') + .contains('Open') + .and('be.visible'); + cy.vote_for_proposal('for'); + cy.get_proposal_information_from_table('State') + .contains('Enacted', proposalTimeout) + .and('be.visible'); + }); + + // 3001-VOTE-048 3001-VOTE-049 + it('Able to fail proposal due to lack of participation', function () { + const proposalTitle = 'Add New free form proposal with short enactment'; + const proposalTx = createFreeFormProposalTxBody(); + cy.VegaWalletSubmitProposal(proposalTx); + cy.navigate_to('proposals'); + cy.reload(); + cy.wait_for_spinner(); + cy.get(openProposals).within(() => { + cy.contains(proposalTitle) + .parentsUntil('[data-testid="proposals-list-item"]') + .within(() => cy.get(viewProposalButton).click()); + }); + cy.get_proposal_information_from_table('State') + .contains('Open') + .and('be.visible'); + cy.get_proposal_information_from_table('State') // 3001-VOTE-047 + .contains('Declined', proposalTimeout) + .and('be.visible'); + cy.get_proposal_information_from_table('Rejection reason') + .contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED') + .and('be.visible'); + }); + } +); diff --git a/apps/token-e2e/src/integration/flow/governance-flow.cy.js b/apps/token-e2e/src/integration/flow/governance-flow.cy.js index 2d0a2db6d..1d5802430 100644 --- a/apps/token-e2e/src/integration/flow/governance-flow.cy.js +++ b/apps/token-e2e/src/integration/flow/governance-flow.cy.js @@ -1,4 +1,5 @@ /// + const vegaWalletUnstakedBalance = '[data-testid="vega-wallet-balance-unstaked"]'; const vegaWalletStakedBalances = @@ -11,7 +12,6 @@ const newProposalSubmitButton = '[data-testid="proposal-submit"]'; const dialogCloseButton = '[data-testid="dialog-close"]'; const viewProposalButton = '[data-testid="view-proposal-btn"]'; const openProposals = '[data-testid="open-proposals"]'; -const closedProposals = '[data-testid="closed-proposals"]'; const proposalVoteProgressForPercentage = '[data-testid="vote-progress-indicator-percentage-for"]'; const proposalVoteProgressAgainstPercentage = @@ -23,9 +23,7 @@ const proposalVoteProgressAgainstTokens = const changeVoteButton = '[data-testid="change-vote-button"]'; const proposalDetailsTitle = '[data-testid="proposal-title"]'; const proposalDetailsDescription = '[data-testid="proposal-description"]'; -const proposalStatus = '[data-testid="proposal-status"]'; const rawProposalData = '[data-testid="proposal-data"]'; -const votesTable = '[data-testid="votes-table"]'; const minVoteButton = '[data-testid="min-vote"]'; const maxVoteButton = '[data-testid="max-vote"]'; const voteButtons = '[data-testid="vote-buttons"]'; @@ -787,107 +785,6 @@ context( cy.contains('You voted: Against').should('be.visible'); }); - // 3001-VOTE-006 - it('Able to view enacted proposal', function () { - cy.createMarket(); - cy.reload(); - cy.wait_for_spinner(); - cy.get(closedProposals).within(() => { - cy.get(proposalDetailsTitle).should( - 'have.text', - 'Add Lorem Ipsum market' - ); - cy.get(proposalStatus).should('have.text', 'Enacted '); - cy.get(viewProposalButton).click(); - }); - cy.getByTestId('proposal-type').should('have.text', 'New market'); - cy.get_proposal_information_from_table('State') - .contains('Enacted') - .and('be.visible'); - cy.get(votesTable).within(() => { - cy.contains('Vote passed.').should('be.visible'); - cy.contains('Voting has ended.').should('be.visible'); - }); - }); - - // 3001-VOTE-047 - it('Able to enact freeform proposal', function () { - const proposalTitle = 'Add New free form proposal with short enactment'; - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.sendWalletTxFreeFormProposal(); - cy.navigate_to('proposals'); - cy.reload(); - cy.wait_for_spinner(); - cy.contains(proposalTitle) - .parentsUntil('[data-testid="proposals-list-item"]') - .within(() => cy.get(viewProposalButton).click()); - cy.get_proposal_information_from_table('State') - .contains('Open') - .and('be.visible'); - cy.vote_for_proposal('for'); - cy.get_proposal_information_from_table('State') - .contains('Enacted', epochTimeout) - .and('be.visible'); - }); - - // 3001-VOTE-046 3001-VOTE-044 3001-VOTE-074 3001-VOTE-074 - it('Able to enact proposal by voting', function () { - const proposalTitle = 'Add New proposal with short enactment'; - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.sendWalletTxUpdateNetworkProposal(); - cy.navigate_to('proposals'); - cy.reload(); - cy.wait_for_spinner(); - cy.contains(proposalTitle) - .parentsUntil('[data-testid="proposals-list-item"]') - .within(() => cy.get(viewProposalButton).click()); - cy.get_proposal_information_from_table('State') - .contains('Open') - .and('be.visible'); - cy.vote_for_proposal('for'); - cy.get_proposal_information_from_table('State') // 3001-VOTE-047 - .contains('Passed', txTimeout) - .and('be.visible'); - cy.get_proposal_information_from_table('State') - .contains('Enacted', epochTimeout) - .and('be.visible'); - cy.get(votesTable).within(() => { - cy.contains('Vote passed.').should('be.visible'); - cy.contains('Voting has ended.').should('be.visible'); - }); - cy.get(proposalVoteProgressForPercentage) - .contains('100.00%') - .and('be.visible'); - }); - - // 3001-VOTE-048 3001-VOTE-049 - it('Able to fail proposal due to lack of participation', function () { - const proposalTitle = 'Add New free form proposal with short enactment'; - cy.ensure_specified_unstaked_tokens_are_associated( - this.minProposerBalance - ); - cy.sendWalletTxFreeFormProposal(); - cy.navigate_to('proposals'); - cy.reload(); - cy.wait_for_spinner(); - cy.contains(proposalTitle) - .parentsUntil('[data-testid="proposals-list-item"]') - .within(() => cy.get(viewProposalButton).click()); - cy.get_proposal_information_from_table('State') - .contains('Open') - .and('be.visible'); - cy.get_proposal_information_from_table('State') // 3001-VOTE-047 - .contains('Declined', txTimeout) - .and('be.visible'); - cy.get_proposal_information_from_table('Rejection reason') - .contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED') - .and('be.visible'); - }); - function createRawProposal(proposerBalance) { if (proposerBalance) cy.ensure_specified_unstaked_tokens_are_associated(proposerBalance); diff --git a/apps/token-e2e/src/support/index.js b/apps/token-e2e/src/support/index.js index b795caa83..ae744251e 100644 --- a/apps/token-e2e/src/support/index.js +++ b/apps/token-e2e/src/support/index.js @@ -7,7 +7,7 @@ import './governance.functions.js'; import './wallet-eth.functions.js'; import './wallet-teardown.functions.js'; import './wallet-vega.functions.js'; -import './proposal.functions.js'; +import './proposal.functions.ts'; import registerCypressGrep from '@cypress/grep'; import { aliasGQLQuery } from '@vegaprotocol/cypress'; import { chainIdQuery, statisticsQuery } from '@vegaprotocol/mock'; diff --git a/apps/token-e2e/src/support/proposal.functions.js b/apps/token-e2e/src/support/proposal.functions.js deleted file mode 100644 index 018ed3cc9..000000000 --- a/apps/token-e2e/src/support/proposal.functions.js +++ /dev/null @@ -1,103 +0,0 @@ -import { addSeconds, millisecondsToSeconds } from 'date-fns'; - -const walletName = Cypress.env('vegaWalletName'); -const walletPubKey = Cypress.env('vegaWalletPublicKey'); -const walletLocation = Cypress.env('vegaWalletLocation'); -const walletPassphraseFile = './src/fixtures/wallet/passphrase'; - -Cypress.Commands.add('sendWalletTxUpdateNetworkProposal', () => { - const MIN_CLOSE_SEC = 8; - const MIN_ENACT_SEC = 5; - - const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC); - const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC); - const closingTimestamp = millisecondsToSeconds(closingDate.getTime()); - const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime()); - - cy.exec( - `vegawallet transaction send --wallet ${walletName} --pubkey ${walletPubKey} -p ${walletPassphraseFile} --network DV '{ - "proposalSubmission": { - "rationale": { - "title": "Add New proposal with short enactment", - "description": "E2E enactment test" - }, - "terms": { - "updateNetworkParameter": { - "changes": { - "key": "governance.proposal.updateNetParam.minProposerBalance", - "value": "2" - } - }, - "closingTimestamp": ${closingTimestamp}, - "enactmentTimestamp": ${enactmentTimestamp} - } - } - }' --home ${walletLocation}`, - { failOnNonZeroExit: false } - ) - .its('stderr') - .should('contain', ''); -}); - -Cypress.Commands.add('sendWalletTxUpdateAssetProposal', () => { - const MIN_CLOSE_SEC = 8; - const MIN_ENACT_SEC = 5; - - const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC); - const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC); - const closingTimestamp = millisecondsToSeconds(closingDate.getTime()); - const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime()); - - cy.exec( - `vegawallet transaction send --wallet ${walletName} --pubkey ${walletPubKey} -p ${walletPassphraseFile} --network DV '{ - "proposalSubmission": { - "rationale": { - "title": "Update Asset set to fail", - "description": "E2E fail test" - }, - "terms": { - "updateAsset": { - "assetId": "ebcd94151ae1f0d39a4bde3b21a9c7ae81a80ea4352fb075a92e07608d9c953d", - "changes": { - "quantum": "1", - "erc20": { - "withdrawThreshold": "10", - "lifetimeLimit": "10" - } - } - }, - "closingTimestamp": ${closingTimestamp}, - "enactmentTimestamp": ${enactmentTimestamp} - } - } - }' --home ${walletLocation}`, - { failOnNonZeroExit: false } - ) - .its('stderr') - .should('contain', ''); -}); - -Cypress.Commands.add('sendWalletTxFreeFormProposal', () => { - const MIN_CLOSE_SEC = 5; - - const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC); - const closingTimestamp = millisecondsToSeconds(closingDate.getTime()); - - cy.exec( - `vegawallet transaction send --wallet ${walletName} --pubkey ${walletPubKey} -p ${walletPassphraseFile} --network DV '{ - "proposalSubmission": { - "rationale": { - "title": "Add New free form proposal with short enactment", - "description": "E2E enactment test" - }, - "terms": { - "newFreeform": {}, - "closingTimestamp": ${closingTimestamp} - } - } - }' --home ${walletLocation}`, - { failOnNonZeroExit: false } - ) - .its('stderr') - .should('contain', ''); -}); diff --git a/apps/token-e2e/src/support/proposal.functions.ts b/apps/token-e2e/src/support/proposal.functions.ts new file mode 100644 index 000000000..45760aa57 --- /dev/null +++ b/apps/token-e2e/src/support/proposal.functions.ts @@ -0,0 +1,82 @@ +import { addSeconds, millisecondsToSeconds } from 'date-fns'; +import type { ProposalSubmissionBody } from '@vegaprotocol/wallet'; + +export function createUpdateNetworkProposalTxBody(): ProposalSubmissionBody { + const MIN_CLOSE_SEC = 5; + const MIN_ENACT_SEC = 7; + + const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC); + const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC); + const closingTimestamp = millisecondsToSeconds(closingDate.getTime()); + const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime()); + return { + proposalSubmission: { + rationale: { + title: 'Add New proposal with short enactment', + description: 'E2E enactment test', + }, + terms: { + updateNetworkParameter: { + changes: { + key: 'governance.proposal.updateNetParam.minProposerBalance', + value: '2', + }, + }, + closingTimestamp, + enactmentTimestamp, + }, + }, + }; +} + +export function createUpdateAssetProposalTxBody(): ProposalSubmissionBody { + const MIN_CLOSE_SEC = 5; + const MIN_ENACT_SEC = 7; + + const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC); + const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC); + const closingTimestamp = millisecondsToSeconds(closingDate.getTime()); + const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime()); + return { + proposalSubmission: { + rationale: { + title: 'Update Asset set to fail', + description: 'E2E fail test', + }, + terms: { + updateAsset: { + assetId: + 'ebcd94151ae1f0d39a4bde3b21a9c7ae81a80ea4352fb075a92e07608d9c953d', + changes: { + quantum: '1', + erc20: { + withdrawThreshold: '10', + lifetimeLimit: '10', + }, + }, + }, + closingTimestamp, + enactmentTimestamp, + }, + }, + }; +} + +export function createFreeFormProposalTxBody(): ProposalSubmissionBody { + const MIN_CLOSE_SEC = 7; + + const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC); + const closingTimestamp = millisecondsToSeconds(closingDate.getTime()); + return { + proposalSubmission: { + rationale: { + title: 'Add New free form proposal with short enactment', + description: 'E2E enactment test', + }, + terms: { + newFreeform: {}, + closingTimestamp, + }, + }, + }; +} diff --git a/apps/token/src/app.tsx b/apps/token/src/app.tsx index 31321f7de..525b6f6b2 100644 --- a/apps/token/src/app.tsx +++ b/apps/token/src/app.tsx @@ -24,8 +24,8 @@ import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import { useEthereumConfig } from '@vegaprotocol/web3'; import { useEnvironment, - EnvironmentProvider, NetworkLoader, + useInitializeEnv, } from '@vegaprotocol/environment'; import { createConnectors } from './lib/web3-connectors'; import { ENV } from './config/env'; @@ -166,12 +166,12 @@ const AppContainer = () => { }; function App() { + useInitializeEnv(); + return ( - - - - - + + + ); } diff --git a/apps/token/src/components/nav/nav.spec.tsx b/apps/token/src/components/nav/nav.spec.tsx index 54ed7b30c..3d29a4e38 100644 --- a/apps/token/src/components/nav/nav.spec.tsx +++ b/apps/token/src/components/nav/nav.spec.tsx @@ -1,23 +1,18 @@ import { render, screen, within } from '@testing-library/react'; -import { EnvironmentProvider, Networks } from '@vegaprotocol/environment'; import { MemoryRouter } from 'react-router-dom'; import { Nav } from './nav'; jest.mock('@vegaprotocol/environment', () => ({ ...jest.requireActual('@vegaprotocol/environment'), NetworkSwitcher: () =>
    , + useEnvironment: () => ({ VEGA_ENV: 'MAINNET' }), })); const renderComponent = (initialEntries?: string[]) => { return render( - - -
    diff --git a/apps/trading/client-pages/portfolio/withdrawals-container.tsx b/apps/trading/client-pages/portfolio/withdrawals-container.tsx index c3b5ae32b..3fe597265 100644 --- a/apps/trading/client-pages/portfolio/withdrawals-container.tsx +++ b/apps/trading/client-pages/portfolio/withdrawals-container.tsx @@ -10,7 +10,7 @@ import { VegaWalletContainer } from '../../components/vega-wallet-container'; export const WithdrawalsContainer = () => { const { pubKey, isReadOnly } = useVegaWallet(); - const { data, loading, error } = useDataProvider({ + const { data, loading, error, reload } = useDataProvider({ dataProvider: withdrawalProvider, variables: { partyId: pubKey || '' }, skip: !pubKey, @@ -33,6 +33,7 @@ export const WithdrawalsContainer = () => { error={error} noDataCondition={(data) => !(data && data.length)} noDataMessage={t('No withdrawals')} + reload={reload} /> diff --git a/apps/trading/components/app-loader/app-failure.tsx b/apps/trading/components/app-loader/app-failure.tsx new file mode 100644 index 000000000..0057955ed --- /dev/null +++ b/apps/trading/components/app-loader/app-failure.tsx @@ -0,0 +1,30 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { Button } from '@vegaprotocol/ui-toolkit'; +import { useGlobalStore } from '../../stores'; + +export const AppFailure = ({ + title, + error, +}: { + title: string; + error?: string | null; +}) => { + const { setNodeSwitcher } = useGlobalStore((store) => ({ + nodeSwitcherOpen: store.nodeSwitcherDialog, + setNodeSwitcher: (open: boolean) => + store.update({ nodeSwitcherDialog: open }), + })); + const nonIdealWrapperClasses = + 'h-full min-h-screen flex items-center justify-center'; + return ( +
    +
    +

    {title}

    + {error &&

    {error}

    } + +
    +
    + ); +}; diff --git a/apps/trading/components/app-loader/app-loader.tsx b/apps/trading/components/app-loader/app-loader.tsx new file mode 100644 index 000000000..d8f0495c5 --- /dev/null +++ b/apps/trading/components/app-loader/app-loader.tsx @@ -0,0 +1,96 @@ +import type { InMemoryCacheConfig } from '@apollo/client'; +import { + NetworkLoader, + NodeGuard, + useEnvironment, +} from '@vegaprotocol/environment'; +import { t } from '@vegaprotocol/react-helpers'; +import { MaintenancePage } from '@vegaprotocol/ui-toolkit'; +import { VegaWalletProvider } from '@vegaprotocol/wallet'; +import dynamic from 'next/dynamic'; +import type { ReactNode } from 'react'; +import { AppFailure } from './app-failure'; +import { Web3Provider } from './web3-provider'; + +const DynamicLoader = dynamic(() => import('../preloader/preloader'), { + loading: () => <>Loading..., +}); + +export const AppLoader = ({ children }: { children: ReactNode }) => { + const { error, VEGA_URL, MAINTENANCE_PAGE } = useEnvironment((store) => ({ + error: store.error, + VEGA_URL: store.VEGA_URL, + MAINTENANCE_PAGE: store.MAINTENANCE_PAGE, + })); + + if (MAINTENANCE_PAGE) { + return ; + } + + return ( + } + failure={ + + } + > + } + failure={} + > + + {children} + + + + ); +}; + +const cacheConfig: InMemoryCacheConfig = { + typePolicies: { + Account: { + keyFields: false, + fields: { + balanceFormatted: {}, + }, + }, + Instrument: { + keyFields: false, + }, + TradableInstrument: { + keyFields: ['instrument'], + }, + Product: { + keyFields: ['settlementAsset', ['id']], + }, + MarketData: { + keyFields: ['market', ['id']], + }, + Node: { + keyFields: false, + }, + Withdrawal: { + fields: { + pendingOnForeignChain: { + read: (isPending = false) => isPending, + }, + }, + }, + ERC20: { + keyFields: ['contractAddress'], + }, + PositionUpdate: { + keyFields: false, + }, + AccountUpdate: { + keyFields: false, + }, + Party: { + keyFields: false, + }, + Fees: { + keyFields: false, + }, + }, +}; diff --git a/apps/trading/components/app-loader/index.tsx b/apps/trading/components/app-loader/index.tsx index 9a1565fd9..624edba38 100644 --- a/apps/trading/components/app-loader/index.tsx +++ b/apps/trading/components/app-loader/index.tsx @@ -1,121 +1,3 @@ -import type { ReactNode } from 'react'; -import { useEffect } from 'react'; -import { NetworkLoader, useEnvironment } from '@vegaprotocol/environment'; -import type { InMemoryCacheConfig } from '@apollo/client'; -import { - useEthereumConfig, - createConnectors, - Web3Provider as Web3ProviderInternal, - useWeb3ConnectStore, -} from '@vegaprotocol/web3'; -import { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit'; - -interface AppLoaderProps { - children: ReactNode; -} - -/** - * Component to handle any app initialization, startup queries and other things - * that must happen for it can be used - */ -export function AppLoader({ children }: AppLoaderProps) { - return ( - } cache={cacheConfig}> - {children} - - ); -} - -export const Web3Provider = ({ children }: { children: ReactNode }) => { - const { config, loading, error } = useEthereumConfig(); - const { ETHEREUM_PROVIDER_URL, ETH_LOCAL_PROVIDER_URL, ETH_WALLET_MNEMONIC } = - useEnvironment(); - const [connectors, initializeConnectors] = useWeb3ConnectStore((store) => [ - store.connectors, - store.initialize, - ]); - - useEffect(() => { - if (config?.chain_id) { - return initializeConnectors( - createConnectors( - ETHEREUM_PROVIDER_URL, - Number(config?.chain_id), - ETH_LOCAL_PROVIDER_URL, - ETH_WALLET_MNEMONIC - ), - Number(config.chain_id) - ); - } - }, [ - config?.chain_id, - ETHEREUM_PROVIDER_URL, - initializeConnectors, - ETH_LOCAL_PROVIDER_URL, - ETH_WALLET_MNEMONIC, - ]); - - return ( - { - if (!d) return true; - return d.length < 1; - }} - > - - <>{children} - - - ); -}; - -const cacheConfig: InMemoryCacheConfig = { - typePolicies: { - Account: { - keyFields: false, - fields: { - balanceFormatted: {}, - }, - }, - Instrument: { - keyFields: false, - }, - TradableInstrument: { - keyFields: ['instrument'], - }, - Product: { - keyFields: ['settlementAsset', ['id']], - }, - MarketData: { - keyFields: ['market', ['id']], - }, - Node: { - keyFields: false, - }, - Withdrawal: { - fields: { - pendingOnForeignChain: { - read: (isPending = false) => isPending, - }, - }, - }, - ERC20: { - keyFields: ['contractAddress'], - }, - PositionUpdate: { - keyFields: false, - }, - AccountUpdate: { - keyFields: false, - }, - Party: { - keyFields: false, - }, - Fees: { - keyFields: false, - }, - }, -}; +export * from './app-failure'; +export * from './app-loader'; +export * from './web3-provider'; diff --git a/apps/trading/components/app-loader/web3-provider.tsx b/apps/trading/components/app-loader/web3-provider.tsx new file mode 100644 index 000000000..290d9309c --- /dev/null +++ b/apps/trading/components/app-loader/web3-provider.tsx @@ -0,0 +1,58 @@ +import { + useEthereumConfig, + createConnectors, + Web3Provider as Web3ProviderInternal, + useWeb3ConnectStore, +} from '@vegaprotocol/web3'; +import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; +import { t } from '@vegaprotocol/react-helpers'; +import { useEnvironment } from '@vegaprotocol/environment'; +import type { ReactNode } from 'react'; +import { useEffect } from 'react'; + +export const Web3Provider = ({ children }: { children: ReactNode }) => { + const { config, loading, error } = useEthereumConfig(); + const { ETHEREUM_PROVIDER_URL, ETH_LOCAL_PROVIDER_URL, ETH_WALLET_MNEMONIC } = + useEnvironment(); + const [connectors, initializeConnectors] = useWeb3ConnectStore((store) => [ + store.connectors, + store.initialize, + ]); + + useEffect(() => { + if (config?.chain_id) { + return initializeConnectors( + createConnectors( + ETHEREUM_PROVIDER_URL, + Number(config?.chain_id), + ETH_LOCAL_PROVIDER_URL, + ETH_WALLET_MNEMONIC + ), + Number(config.chain_id) + ); + } + }, [ + config?.chain_id, + ETHEREUM_PROVIDER_URL, + initializeConnectors, + ETH_LOCAL_PROVIDER_URL, + ETH_WALLET_MNEMONIC, + ]); + + return ( + { + if (!d) return true; + return d.length < 1; + }} + noDataMessage={t('Could not fetch Ethereum configuration')} + > + + <>{children} + + + ); +}; diff --git a/apps/trading/components/footer/footer.spec.tsx b/apps/trading/components/footer/footer.spec.tsx index 687a3fbe6..b44e54c48 100644 --- a/apps/trading/components/footer/footer.spec.tsx +++ b/apps/trading/components/footer/footer.spec.tsx @@ -1,57 +1,38 @@ import { fireEvent, render, screen } from '@testing-library/react'; -import { Footer, NodeHealth } from './footer'; -import { useEnvironment } from '@vegaprotocol/environment'; +import { NodeUrl, NodeHealth } from './footer'; -jest.mock('@vegaprotocol/environment'); - -describe('Footer', () => { +describe('NodeUrl', () => { it('can open node switcher by clicking the node url', () => { const mockOpenNodeSwitcher = jest.fn(); - const node = 'n99.somenetwork.vega.xyz'; + const node = 'https://api.n99.somenetwork.vega.xyz'; - // @ts-ignore mock env hook - useEnvironment.mockImplementation(() => ({ - VEGA_URL: `https://api.${node}/graphql`, - blockDifference: 0, - setNodeSwitcherOpen: mockOpenNodeSwitcher, - })); + render(); - render(