Compare commits

..
Author SHA1 Message Date
Matthew Russell ab27b52845 chore: skip broken test 2023-11-13 23:31:24 -08:00
Matthew Russell 9084ea0afb chore: use id for web3 modal target 2023-11-13 23:02:58 -08:00
Matthew Russell 437a3ab495 chore: remoe imports and just use ts-ignore 2023-11-13 17:40:01 -08:00
Matthew Russell 2491c1c118 chore: add path for yarn cache 2023-11-13 17:01:10 -08:00
Matthew Russell 75d9166260 chore: fix path to nvmrc 2023-11-13 16:19:54 -08:00
Matthew Russell 07175d2854 chore: move setup node after checkout 2023-11-13 16:00:07 -08:00
Matthew Russell 1b8f5d0952 chore: re add setup node v4 2023-11-13 14:11:50 -08:00
Matthew Russell 53f8bb148b chore: update setup node action version 2023-11-13 14:01:15 -08:00
Matthew Russell 238d9596fb chore: add nodejs setup 2023-11-13 13:40:16 -08:00
Matthew Russell 67c178c56e chore: fix typescript errors in governance test 2023-11-13 12:58:58 -08:00
Matthew Russell 6f817d2fad chore: ignore setup tests from linting 2023-11-13 12:18:51 -08:00
Matthew Russell 50013bdf95 chore: ignore unsafe to chain command 2023-11-13 12:02:45 -08:00
Matthew Russell 8e91a6db3d fix: incorrect undefined check on window 2023-11-13 11:53:19 -08:00
Matthew Russell ceea736c82 chore: nx migration to latest 2023-11-13 11:42:44 -08:00
Matthew Russell 9629eb21ac chore: update react types 2023-11-13 09:59:53 -08:00
Matthew Russell 24c9d9aed7 chore: remove unused import 2023-11-13 09:18:20 -08:00
Matthew Russell af746f05aa chore: ensure nvmrc is used for setup node actions 2023-11-13 09:00:51 -08:00
Matthew Russell 74661c4ccd chore: fix lint warnings 2023-11-13 08:51:20 -08:00
Edd a42b359f11 fix(explorer): fix mocks for broken unit test 2023-11-13 15:12:57 +00:00
Matthew Russell 8f78626627 chore: disable test with with eslint ignore 2023-11-12 23:55:39 -08:00
Matthew Russell becd62996c chore: update readme 2023-11-12 23:51:31 -08:00
Matthew Russell e565b3887c chore: comment 2023-11-12 23:46:19 -08:00
Matthew Russell 0165063ad5 fix: order book column tests 2023-11-12 23:40:09 -08:00
Matthew Russell b8b0bf7586 fix: transfer form tooltip tests 2023-11-12 23:02:43 -08:00
Matthew Russell b029857830 fix: market link text for not found market 2023-11-12 22:42:51 -08:00
Matthew Russell a914e67061 chore: sure up types and fix tests, skip one for now 2023-11-12 11:00:59 -08:00
Matthew Russell 4e9117aca9 chore: add missing dep for candles-chart tests 2023-11-12 11:00:33 -08:00
Matthew Russell bda7430484 chore: ignore ts errors for copy component 2023-11-11 14:28:13 -08:00
Matthew Russell a90f631a3e test: fix use node health hook 2023-11-11 13:58:50 -08:00
Matthew Russell a196c96156 chore: fix link tests 2023-11-11 13:53:07 -08:00
Matthew Russell 576c3db59e chore: update to latest stable node version 2023-11-11 13:50:26 -08:00
Matthew Russell 2ecb518d39 chore: bump node version 2023-11-11 13:37:42 -08:00
Matthew Russell 4cbee21cc5 chore: add missing d3 deps, fix imports for jest 2023-11-11 13:36:56 -08:00
Matthew Russell 2c2fab1da1 chore: add prettier tailwind plugin, update node version 2023-11-11 10:36:29 -08:00
428 changed files with 4177 additions and 14443 deletions
+1 -2
View File
@@ -73,8 +73,7 @@
"error",
{
"prefer": "type-imports",
"disallowTypeAnnotations": true,
"fixStyle": "inline-type-imports"
"disallowTypeAnnotations": true
}
],
"curly": ["error", "multi-line"]
+1 -1
View File
@@ -205,7 +205,7 @@ jobs:
console-e2e:
needs: [build-sources, check-e2e-needed]
name: '(CI) trading e2e python'
name: '(CI) console python'
uses: ./.github/workflows/console-test-run.yml
secrets: inherit
if: needs.check-e2e-needed.outputs.run-tests == 'true' && contains(needs.build-sources.outputs.projects, 'trading')
+18 -15
View File
@@ -10,7 +10,7 @@ on:
inputs:
console-test-branch:
type: choice
description: 'main: v0.72.14, develop: v0.73.4'
description: 'main: v0.72.14, develop: v0.73.0-preview7'
options:
- main
- develop
@@ -153,19 +153,25 @@ jobs:
run: |
docker load --input /tmp/console-image.tar
docker image ls -a
#----------------------------------------------
# check-out frontend-monorepo
# check-out tests repo
#----------------------------------------------
- name: Checkout frontend-monorepo
- name: Checkout console test repo
uses: actions/checkout@v3
with:
ref: ${{ inputs.github-sha || github.sha }}
#----------------------------------------------
# get vega version
#----------------------------------------------
- name: Set VEGA_VERSION from .env
id: set_vega_version
run: echo "VEGA_VERSION=$(grep VEGA_VERSION apps/trading/e2e/.env | cut -d '=' -f2)" >> $GITHUB_ENV
repository: vegaprotocol/console-test
ref: ${{ needs.console-test-branch.outputs.console-branch }}
- name: Load console test envs
id: console-test-env
uses: falti/dotenv-action@v1.0.4
with:
path: '.env.${{ needs.console-test-branch.outputs.console-branch }}'
export-variables: true
keys-case: upper
log-variables: true
#----------------------------------------------
# ----- Setup python -----
#----------------------------------------------
@@ -188,25 +194,22 @@ jobs:
#----------------------------------------------
- name: Install dependencies
run: poetry install --no-interaction --no-root
working-directory: apps/trading/e2e
#----------------------------------------------
# install vega binaries
#----------------------------------------------
- name: Install vega binaries
run: poetry run python -m vega_sim.tools.load_binaries --force --version ${{ env.VEGA_VERSION }}
working-directory: apps/trading/e2e
#----------------------------------------------
# install playwrightworking-directory: apps/trading/e2e
# install playwright
#----------------------------------------------
- name: install playwright
run: poetry run playwright install --with-deps chromium
working-directory: apps/trading/e2e
#----------------------------------------------
# run tests
#----------------------------------------------
- name: Run tests
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 4 --dist loadfile --durations=15
working-directory: apps/trading/e2e
#----------------------------------------------
# upload traces
#----------------------------------------------
+2 -9
View File
@@ -48,16 +48,9 @@ cypress.env.json
# Next.js
.next
# cypress
#cypress
/apps/**/cypress/reports/
/apps/**/cypress/downloads/
/apps/**/fixtures/wallet/node**
# apps/trading/e2e
__pycache__/
apps/trading/e2e/logs/
apps/trading/e2e/.pytest_cache/
apps/trading/e2e/traces/
.nx/cache
.nx/cache
+1 -12
View File
@@ -1,7 +1,6 @@
# Add files here to ignore them from prettier formatting
/dist
/dist-result
/coverage
__generated__
__generated___
@@ -10,14 +9,4 @@ apps/static/src/assets/devnet-tranches.json
apps/static/src/assets/mainnet-tranches.json
apps/static/src/assets/testnet-tranches.json
/apps/**/cypress/reports/
/apps/**/cypress/downloads/
/.nx/cache
# apps/trading/e2e
__pycache__/
apps/trading/e2e/logs/
apps/trading/e2e/.pytest_cache/
apps/trading/e2e/traces/
.pytest_cache/
/.nx/cache
+1
View File
@@ -1,3 +1,4 @@
{
"plugins": ["prettier-plugin-tailwindcss"],
"singleQuote": true
}
+4
View File
@@ -0,0 +1,4 @@
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
+9
View File
@@ -74,6 +74,15 @@
]
}
},
"build-netlify": {
"executor": "nx:run-commands",
"options": {
"commands": [
"cp apps/explorer/netlify.toml netlify.toml",
"nx build explorer"
]
}
},
"build-spec": {
"executor": "nx:run-commands",
"outputs": [],
@@ -1,5 +1,5 @@
import { useAssetDataProvider } from '@vegaprotocol/assets';
import { addDecimalsFixedFormatNumber } from '@vegaprotocol/utils';
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
import { AssetLink } from '../links';
export type AssetBalanceProps = {
@@ -23,12 +23,12 @@ const AssetBalance = ({
const label =
!loading && asset && asset.decimals
? addDecimalsFixedFormatNumber(price, asset.decimals)
? addDecimalsFormatNumber(price, asset.decimals)
: price;
return (
<div className="inline-block">
<span className="font-mono">{label}</span>{' '}
<span>{label}</span>{' '}
{showAssetLink && asset?.id ? (
<AssetLink showAssetSymbol={showAssetSymbol} assetId={assetId} />
) : null}
@@ -1,25 +1,20 @@
import { useMemo } from 'react';
import {
useAssetTypeMapping,
useAssetStatusMapping,
type AssetFieldsFragment,
} from '@vegaprotocol/assets';
import type { AssetFieldsFragment } from '@vegaprotocol/assets';
import { AssetTypeMapping, AssetStatusMapping } from '@vegaprotocol/assets';
import { t } from '@vegaprotocol/i18n';
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import { type AgGridReact } from 'ag-grid-react';
import type { AgGridReact } from 'ag-grid-react';
import { AgGrid } from '@vegaprotocol/datagrid';
import { type VegaICellRendererParams } from '@vegaprotocol/datagrid';
import type { VegaICellRendererParams } from '@vegaprotocol/datagrid';
import { useRef, useLayoutEffect } from 'react';
import { BREAKPOINT_MD } from '../../config/breakpoints';
import { useNavigate } from 'react-router-dom';
import { type RowClickedEvent, ColDef } from 'ag-grid-community';
import type { RowClickedEvent, ColDef } from 'ag-grid-community';
type AssetsTableProps = {
data: AssetFieldsFragment[] | null;
};
export const AssetsTable = ({ data }: AssetsTableProps) => {
const assetTypeMapping = useAssetTypeMapping();
const assetStatusMapping = useAssetStatusMapping();
const navigate = useNavigate();
const ref = useRef<AgGridReact>(null);
const showColumnsOnDesktop = () => {
@@ -52,14 +47,14 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
field: 'source.__typename',
hide: window.innerWidth < BREAKPOINT_MD,
valueFormatter: ({ value }: { value?: string }) =>
value ? assetTypeMapping[value].value : '',
value ? AssetTypeMapping[value].value : '',
},
{
headerName: t('Status'),
field: 'status',
hide: window.innerWidth < BREAKPOINT_MD,
valueFormatter: ({ value }: { value?: string }) =>
value ? assetStatusMapping[value].value : '',
value ? AssetStatusMapping[value].value : '',
},
{
colId: 'actions',
@@ -74,7 +69,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
}: VegaICellRendererParams<AssetFieldsFragment, 'id'>) =>
value ? (
<ButtonLink
onClick={() => {
onClick={(e) => {
navigate(value);
}}
>
@@ -85,7 +80,7 @@ export const AssetsTable = ({ data }: AssetsTableProps) => {
),
},
],
[navigate, assetStatusMapping, assetTypeMapping]
[navigate]
);
return (
@@ -2,18 +2,18 @@ import { useMemo } from 'react';
import { getAsset, type MarketFieldsFragment } from '@vegaprotocol/markets';
import { t } from '@vegaprotocol/i18n';
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import { type AgGridReact } from 'ag-grid-react';
import { type ColDef } from 'ag-grid-community';
import type { AgGridReact } from 'ag-grid-react';
import type { ColDef } from 'ag-grid-community';
import { AgGrid } from '@vegaprotocol/datagrid';
import {
type VegaICellRendererParams,
type VegaValueGetterParams,
import type {
VegaICellRendererParams,
VegaValueGetterParams,
} from '@vegaprotocol/datagrid';
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 type { RowClickedEvent } from 'ag-grid-community';
import { Link, useNavigate } from 'react-router-dom';
type MarketsTableProps = {
@@ -1,14 +1,14 @@
import { type ProposalListFieldsFragment } from '@vegaprotocol/proposals';
import type { ProposalListFieldsFragment } from '@vegaprotocol/proposals';
import { VoteProgress } from '@vegaprotocol/proposals';
import { type AgGridReact } from 'ag-grid-react';
import type { AgGridReact } from 'ag-grid-react';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import { AgGrid } from '@vegaprotocol/datagrid';
import {
type VegaICellRendererParams,
type VegaValueFormatterParams,
import type {
VegaICellRendererParams,
VegaValueFormatterParams,
} from '@vegaprotocol/datagrid';
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
import { type RowClickedEvent, ColDef } from 'ag-grid-community';
import type { RowClickedEvent, ColDef } from 'ag-grid-community';
import { getDateTimeFormat } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import {
@@ -105,7 +105,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => {
? new BigNumber(0)
: yesTokens.multipliedBy(100).dividedBy(totalTokensVoted);
return (
<div className="flex h-full items-center justify-center pt-2 uppercase">
<div className="flex items-center justify-center h-full pt-2 uppercase">
<VoteProgress
threshold={requiredMajorityPercentage}
progress={yesPercentage}
@@ -15,7 +15,6 @@ import isUndefined from 'lodash/isUndefined';
import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response';
import { TxDetailsChainEventWithdrawal } from './tx-erc20-withdrawal';
import { TxDetailsChainEventErc20AssetDelist } from './tx-erc20-asset-delist';
import { TxDetailsContractCall } from './tx-contract-call';
interface ChainEventProps {
txData: BlockExplorerTransactionResult | undefined;
@@ -39,7 +38,7 @@ export const ChainEvent = ({ txData }: ChainEventProps) => {
return null;
}
const { builtin, erc20, erc20Multisig, stakingEvent, contractCall } =
const { builtin, erc20, erc20Multisig, stakingEvent } =
txData.command.chainEvent;
// Builtin Asset events
@@ -141,10 +140,6 @@ export const ChainEvent = ({ txData }: ChainEventProps) => {
}
}
if (contractCall) {
return <TxDetailsContractCall contractCall={contractCall} />;
}
// If we hit this return, tx-shared-details should give a basic overview
return null;
};
@@ -1,26 +0,0 @@
import { decodeEthCallResult } from './tx-contract-call';
import { base64 } from 'ethers/lib/utils';
import { defaultAbiCoder } from '@ethersproject/abi';
import { BigNumber } from '@ethersproject/bignumber';
describe('decodeEthCallResult', () => {
it('should decode contractData correctly (mocked)', () => {
const mockContractData = base64.encode(
defaultAbiCoder.encode(['int256'], [BigNumber.from(123)])
);
const result = decodeEthCallResult(mockContractData);
expect(result).toBe('123');
});
it('should decode contractData correctly (known data)', () => {
const mockContractData = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADH8cueyY=';
const result = decodeEthCallResult(mockContractData);
expect(result).toBe('3435020581670');
});
it('should return "-" when an error occurs', () => {
const mockContractData = 'invalid_data';
const result = decodeEthCallResult(mockContractData);
expect(result).toBe('-');
});
});
@@ -1,88 +0,0 @@
import { TableCell, TableRow } from '../../../table';
import { t } from '@vegaprotocol/i18n';
import {
EthExplorerLink,
EthExplorerLinkTypes,
} from '../../../links/eth-explorer-link/eth-explorer-link';
import type { components } from '../../../../../types/explorer';
import { defaultAbiCoder, base64 } from 'ethers/lib/utils';
import { BigNumber } from 'ethers';
import OracleLink from '../../../links/oracle-link/oracle-link';
import { useExplorerOracleSpecByIdQuery } from '../../../../routes/oracles/__generated__/Oracles';
import { OracleEthSource } from '../../../../routes/oracles/components/oracle-eth-source';
/**
* Decodes the b64/ABIcoded result from an eth cal
* @param data
* @returns
*/
export function decodeEthCallResult(contractData: string): string {
try {
const rawResult = defaultAbiCoder.decode(
['int256'],
base64.decode(contractData)
);
// Finally, convert the resulting BigNumber in to a string
const res = BigNumber.from(rawResult[0]).toString();
return res;
} catch (e) {
return '-';
}
}
interface TxDetailsContractCallProps {
contractCall: components['schemas']['vegaEthContractCallEvent'];
}
export const TxDetailsContractCall = ({
contractCall,
}: TxDetailsContractCallProps) => {
const { data } = useExplorerOracleSpecByIdQuery({
variables: {
id: contractCall.specId || '1',
},
});
if (!contractCall || !contractCall.result) {
return null;
}
return (
<>
{contractCall.specId && (
<TableRow modifier="bordered">
<TableCell>{t('Oracle')}</TableCell>
<TableCell>
<OracleLink
id={contractCall.specId}
hasSeenOracleReports={true}
status={data?.oracleSpec?.dataSourceSpec.spec.status || '-'}
/>
</TableCell>
</TableRow>
)}
{contractCall.blockHeight && (
<TableRow modifier="bordered">
<TableCell>{t('ETH block')}</TableCell>
<TableCell>
<EthExplorerLink
id={contractCall.blockHeight}
type={EthExplorerLinkTypes.block}
/>
</TableCell>
</TableRow>
)}
{data?.oracleSpec?.dataSourceSpec && (
<OracleEthSource
sourceType={data.oracleSpec.dataSourceSpec.spec.data.sourceType}
/>
)}
<TableRow modifier="bordered">
<TableCell>{t('Result')}</TableCell>
<TableCell>{decodeEthCallResult(contractCall.result)}</TableCell>
</TableRow>
</>
);
};
@@ -1,11 +1,51 @@
import { t } from '@vegaprotocol/i18n';
import { TxDetailsShared } from './shared/tx-details-shared';
import { TableWithTbody } from '../../table';
import { defaultAbiCoder, base64 } from 'ethers/lib/utils';
import { ChainEvent } from './chain-events';
import { BigNumber } from 'ethers';
import type { AbiType } from '../../../lib/encoders/abis/abi-types';
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
interface AbiOutput {
type: AbiType;
internalType: AbiType;
name: string;
}
/**
* Decodes the b64/ABIcoded result from an eth cal
* @param data
* @returns
*/
export function decodeEthCallResult(
data: BlockExplorerTransactionResult
): string {
const ethResult = data.command.chainEvent?.contractCall.result;
try {
// Decode the result string: base64 => uint8array
const data = base64.decode(ethResult);
// Parse the escaped ABI in to an object
const abi = JSON.parse(
'[{"inputs":[],"name":"latestAnswer","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"}]'
);
// Pull the expected types out of the Oracles ABI
const types: AbiType[] = abi[0].outputs.map((o: AbiOutput) => o.type);
const rawResult = defaultAbiCoder.decode(types, data);
// Finally, convert the resulting BigNumber in to a string
const res = BigNumber.from(rawResult[0]).toString();
return res;
} catch (e) {
return '-';
}
}
interface TxDetailsChainEventProps {
txData: BlockExplorerTransactionResult | undefined;
pubKey: string | undefined;
@@ -3,8 +3,8 @@ import { DATA_SOURCES } from '../../../config';
import { t } from '@vegaprotocol/i18n';
import { useFetch } from '@vegaprotocol/react-helpers';
import { TxDetailsOrder } from './tx-order';
import { type BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
import { type TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
import { TxDetailsHeartbeat } from './tx-hearbeat';
import { TxDetailsGeneric } from './tx-generic';
import { TxDetailsBatch } from './tx-batch';
@@ -1,7 +1,7 @@
import { Table, TableRow } from '../table';
import { t } from '@vegaprotocol/i18n';
import { useFetch } from '@vegaprotocol/react-helpers';
import { type BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
import { getTxsDataUrl } from '../../hooks/get-txs-data-url';
import { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit';
import EmptyList from '../empty-list/empty-list';
@@ -22,7 +22,7 @@ export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
return (
<AsyncRenderer data={data} error={error} loading={!!loading}>
{data && data.transactions.length > 0 ? (
<div className="mb-28 overflow-x-auto whitespace-nowrap">
<div className="overflow-x-auto whitespace-nowrap mb-28">
<Table>
<thead>
<TableRow modifier="bordered" className="font-mono">
+5 -5
View File
@@ -1,14 +1,14 @@
import { useSearchParams } from 'react-router-dom';
import { type URLSearchParamsInit } from 'react-router-dom';
import type { URLSearchParamsInit } from 'react-router-dom';
import { useCallback } from 'react';
import { useFetch } from '@vegaprotocol/react-helpers';
import {
type BlockExplorerTransactionResult,
type BlockExplorerTransactions,
import type {
BlockExplorerTransactionResult,
BlockExplorerTransactions,
} from '../routes/types/block-explorer-response';
import isNumber from 'lodash/isNumber';
import { AllFilterOptions } from '../components/txs/tx-filter';
import { type FilterOption } from '../components/txs/tx-filter';
import type { FilterOption } from '../components/txs/tx-filter';
import { BE_TXS_PER_REQUEST, getTxsDataUrl } from './get-txs-data-url';
export function getTypeFilters(filters?: Set<FilterOption>) {
@@ -9,13 +9,11 @@ import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
import { useState } from 'react';
import { PageTitle } from '../../components/page-helpers/page-title';
type Params = { assetId: string };
export const AssetPage = () => {
useDocumentTitle(['Assets']);
useScrollToLocation();
const { assetId } = useParams<Params>();
const { assetId } = useParams<{ assetId: string }>();
const { data, loading, error } = useAssetDataProvider(assetId || '');
const title = data ? data.name : error ? t('Asset not found') : '';
@@ -43,7 +41,7 @@ export const AssetPage = () => {
loading={loading}
error={error}
>
<div className="relative h-full">
<div className="h-full relative">
<AssetDetailsTable asset={data as AssetFieldsFragment} />
</div>
</AsyncRenderer>
@@ -1,8 +1,8 @@
import { useCallback, useState } from 'react';
import { DATA_SOURCES } from '../../../config';
import {
type BlockMeta,
type TendermintBlockchainResponse,
import type {
BlockMeta,
TendermintBlockchainResponse,
} from '../tendermint-blockchain-response';
import { RouteTitle } from '../../../components/route-title';
import { BlocksRefetch } from '../../../components/blocks';
@@ -17,10 +17,8 @@ import { NodeLink } from '../../../components/links';
import { useDocumentTitle } from '../../../hooks/use-document-title';
import EmptyList from '../../../components/empty-list/empty-list';
type Params = { block: string };
const Block = () => {
const { block } = useParams<Params>();
const { block } = useParams<{ block: string }>();
useDocumentTitle(['Blocks', `Block #${block}`]);
const {
state: { data: blockData, loading, error },
@@ -31,7 +29,7 @@ const Block = () => {
<RouteTitle data-testid="block-header">{t(`BLOCK ${block}`)}</RouteTitle>
<AsyncRenderer data={blockData} error={error} loading={!!loading}>
<>
<div className="mb-8 grid grid-cols-2 gap-2">
<div className="grid grid-cols-2 gap-2 mb-8">
<Link
data-testid="previous-block"
to={`/${Routes.BLOCKS}/${Number(block) - 1}`}
@@ -3,7 +3,7 @@ import { useFetch } from '@vegaprotocol/react-helpers';
import { RouteTitle } from '../../components/route-title';
import { AsyncRenderer, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { DATA_SOURCES } from '../../config';
import { type TendermintGenesisResponse } from './tendermint-genesis-response';
import type { TendermintGenesisResponse } from './tendermint-genesis-response';
import { useDocumentTitle } from '../../hooks/use-document-title';
const Genesis = () => {
@@ -11,12 +11,10 @@ import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
import { marketInfoWithDataProvider } from '@vegaprotocol/markets';
import { PageTitle } from '../../components/page-helpers/page-title';
type Params = { marketId: string };
export const MarketPage = () => {
useScrollToLocation();
const { marketId } = useParams<Params>();
const { marketId } = useParams<{ marketId: string }>();
const { data, loading, error } = useDataProvider({
dataProvider: marketInfoWithDataProvider,
@@ -1,10 +1,8 @@
import { getNodes } from '@vegaprotocol/utils';
import { MarketLink } from '../../../components/links';
import { TableRow, TableCell, TableHeader } from '../../../components/table';
import {
useExplorerOracleFormMarketsQuery,
type ExplorerOracleForMarketsMarketFragment,
} from '../__generated__/OraclesForMarkets';
import type { ExplorerOracleForMarketsMarketFragment } from '../__generated__/OraclesForMarkets';
import { useExplorerOracleFormMarketsQuery } from '../__generated__/OraclesForMarkets';
interface OracleMarketsProps {
id: string;
@@ -9,10 +9,8 @@ import { AsyncRenderer, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import filter from 'recursive-key-filter';
import { TruncateInline } from '../../../components/truncate/truncate';
type Params = { id: string };
export const Oracle = () => {
const { id } = useParams<Params>();
const { id } = useParams<{ id: string }>();
useDocumentTitle(['Oracle', `Oracle #${truncateByChars(id || '1', 5, 5)}`]);
@@ -6,10 +6,8 @@ import { useDocumentTitle } from '../../../../hooks/use-document-title';
import { PartyAccounts } from '../components/party-accounts';
type Params = { party: string };
const PartyAccountsByAsset = () => {
const { party } = useParams<Params>();
const { party } = useParams<{ party: string }>();
useDocumentTitle(['Public keys', party || '-']);
const partyId = toNonHex(party ? party : '');
@@ -1,7 +1,6 @@
import { useExplorerPartyAssetsQuery } from '../__generated__/Party-assets';
import { AssetLink, MarketLink } from '../../../../components/links';
import AssetBalance from '../../../../components/asset-balance/asset-balance';
import { AccountTypeMapping } from '@vegaprotocol/types';
import { AccountManager } from '@vegaprotocol/accounts';
import { useCallback } from 'react';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
interface PartyAccountsProps {
partyId: string;
@@ -13,71 +12,21 @@ interface PartyAccountsProps {
* appearing first and... tbd
*/
export const PartyAccounts = ({ partyId }: PartyAccountsProps) => {
const { data } = useExplorerPartyAssetsQuery({
variables: { partyId },
});
const party = data?.partiesConnection?.edges[0]?.node;
const accounts =
party?.accountsConnection?.edges?.filter((edge) => edge?.node) || [];
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
const onClickAsset = useCallback(
(assetId?: string) => {
assetId && openAssetDetailsDialog(assetId);
},
[openAssetDetailsDialog]
);
return (
<div className="block min-h-44 h-60 4 w-full border-red-800 relative">
<table>
<thead>
<tr>
<th className="text-right px-4">Balance</th>
<th className="text-left px-4">Type</th>
<th className="text-left px-4">Market</th>
<th className="text-left px-4">Asset</th>
</tr>
</thead>
<tbody>
{accounts
.sort((a, b) => {
// Sort by asset id, then market id, with general accounts first
if (!a) {
return 1;
}
if (!b) {
return -1;
}
if (a.node.asset.id !== b.node.asset.id) {
return a.node.asset.id.localeCompare(b.node.asset.id);
}
if (a.node.type === 'ACCOUNT_TYPE_GENERAL') return -1;
if (b.node.type === 'ACCOUNT_TYPE_GENERAL') return 1;
if (a.node.market && b.node.market) {
return a.node.market.id.localeCompare(b.node.market.id);
} else {
return a.node.type.localeCompare(b.node.type);
}
})
.map((e) => {
if (!e) return null;
const { type, asset, balance, market } = e.node;
return (
<tr className="border-t border-neutral-300 dark:border-neutral-600">
<td className="px-4 text-right">
<AssetBalance
assetId={asset.id}
price={balance}
showAssetSymbol={true}
/>
</td>
<td className="px-4">{AccountTypeMapping[type]}</td>
<td className="px-4">
{market?.id ? <MarketLink id={market.id} /> : '-'}
</td>
<td className="px-4">
<AssetLink assetId={asset.id} />
</td>
</tr>
);
})}
</tbody>
</table>
<AccountManager
partyId={partyId}
onClickAsset={onClickAsset}
isReadOnly={true}
/>
</div>
);
};
@@ -19,13 +19,11 @@ import type { FilterOption } from '../../../components/txs/tx-filter';
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
import { useSearchParams } from 'react-router-dom';
type Params = { party: string };
const Party = () => {
const [params] = useSearchParams();
const [filters, setFilters] = useState(new Set(AllFilterOptions));
const { party } = useParams<Params>();
const { party } = useParams<{ party: string }>();
useDocumentTitle(['Public keys', party || '-']);
const navigate = useNavigate();
@@ -62,7 +60,7 @@ const Party = () => {
if (!isValidPartyId(partyId)) {
return (
<div className="mx-auto max-w-sm">
<div className="max-w-sm mx-auto">
<Notification
message={t('Invalid party ID')}
intent={Intent.Danger}
@@ -86,7 +84,7 @@ const Party = () => {
truncateEnd={visibleChars}
/>
<div className="grid w-full grid-flow-row grid-cols-1 md:grid-flow-col md:grid-cols-2 md:space-x-4">
<div className="grid md:grid-flow-col grid-flow-row md:space-x-4 grid-cols-1 md:grid-cols-2 w-full">
<PartyBlockAccounts
accountError={AccountError}
accountLoading={AccountLoading}
@@ -4,15 +4,13 @@ import { useFetch } from '@vegaprotocol/react-helpers';
import { DATA_SOURCES } from '../../../config';
import { RenderFetched } from '../../../components/render-fetched';
import { TxDetails } from './tx-details';
import { type BlockExplorerTransaction } from '../../../routes/types/block-explorer-response';
import type { BlockExplorerTransaction } from '../../../routes/types/block-explorer-response';
import { toNonHex } from '../../../components/search/detect-search';
import { PageHeader } from '../../../components/page-header';
import { useDocumentTitle } from '../../../hooks/use-document-title';
type Params = { txHash: string };
const Tx = () => {
const { txHash } = useParams<Params>();
const { txHash } = useParams<{ txHash: string }>();
const hash = txHash ? toNonHex(txHash) : '';
let errorMessage: string | undefined = undefined;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"extends": ["plugin:cypress/recommended", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "cypress"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
@@ -31,7 +31,7 @@ import {
switchVegaWalletPubKey,
vegaWalletSetSpecifiedApprovalAmount,
} from '../../support/wallet-functions';
import { type testFreeformProposal } from '../../support/common-interfaces';
import type { testFreeformProposal } from '../../support/common-interfaces';
import { formatDateWithLocalTimezone } from '@vegaprotocol/utils';
import {
createGovernanceTransferProposalTxBody,
@@ -34,7 +34,7 @@ import {
vegaWalletTeardown,
} from '../../support/wallet-functions';
import { ethereumWalletConnect } from '../../support/wallet-eth.functions';
import { type testFreeformProposal } from '../../support/common-interfaces';
import type { testFreeformProposal } from '../../support/common-interfaces';
const vegaWalletStakedBalances = 'vega-wallet-balance-staked-validators';
const vegaWalletAssociatedBalance = 'associated-amount';
@@ -1,4 +1,4 @@
import { type testFreeformProposal } from '../../support/common-interfaces';
import type { testFreeformProposal } from '../../support/common-interfaces';
import {
navigateTo,
navigation,
@@ -302,17 +302,14 @@ context(
cy.getByTestId(vegaWalletCurrencyTitle)
.contains(name)
.parent() // back to currency-title
.parent() // back to container
.within(() => {
cy.get(
'[data-account-type="account_type_general"] [data-value]'
).should((elementAmount) => {
const displayedAmount = parseFloat(elementAmount.text());
// @ts-ignore clash between jest and cypress
expect(displayedAmount).be.gte(expectedAmount);
});
.parent()
.siblings(txTimeout)
.should((elementAmount) => {
const displayedAmount = parseFloat(elementAmount.text());
// @ts-ignore clash between jest and cypress
expect(displayedAmount).be.gte(expectedAmount);
});
cy.getByTestId(vegaWalletCurrencyTitle)
.contains(name)
.parent()
@@ -256,7 +256,10 @@ export function validateWalletCurrency(
.parent()
.parent()
.within(() => {
cy.get('[data-value]', txTimeout).should('have.text', expectedAmount);
cy.getByTestId('currency-value', txTimeout).should(
'have.text',
expectedAmount
);
});
}
+2 -1
View File
@@ -35,5 +35,6 @@ NX_SUCCESSOR_MARKETS=true
NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=false
NX_UPDATE_MARKET_STATE=false
NX_REFERRALS=true
NX_REFERRALS=false
NX_GOVERNANCE_TRANSFERS=false
NX_VOLUME_DISCOUNTS=false
+2 -1
View File
@@ -31,8 +31,9 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket
CYPRESS_FAIRGROUND=false
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_SUCCESSOR_MARKETS=false
NX_METAMASK_SNAPS=false
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_VOLUME_DISCOUNTS=true
+1
View File
@@ -28,3 +28,4 @@ NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_VOLUME_DISCOUNTS=true
+5 -4
View File
@@ -22,8 +22,9 @@ NX_TENDERMINT_URL=https://be.vega.community
NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_SUCCESSOR_MARKETS=false
NX_METAMASK_SNAPS=false
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_PRODUCT_PERPETUALS=false
NX_UPDATE_MARKET_STATE=false
NX_REFERRALS=false
NX_VOLUME_DISCOUNTS=false
+5 -4
View File
@@ -21,8 +21,9 @@ NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_SUCCESSOR_MARKETS=false
NX_METAMASK_SNAPS=false
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_PRODUCT_PERPETUALS=false
NX_UPDATE_MARKET_STATE=false
NX_REFERRALS=false
NX_VOLUME_DISCOUNTS=false
+1
View File
@@ -25,3 +25,4 @@ NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_GOVERNANCE_TRANSFERS=true
NX_VOLUME_DISCOUNTS=true
+1
View File
@@ -29,3 +29,4 @@ NX_METAMASK_SNAPS=true
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_VOLUME_DISCOUNTS=true
+5 -4
View File
@@ -20,8 +20,9 @@ NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks
NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true
NX_SUCCESSOR_MARKETS=false
NX_METAMASK_SNAPS=false
NX_PRODUCT_PERPETUALS=true
NX_UPDATE_MARKET_STATE=true
NX_REFERRALS=true
NX_PRODUCT_PERPETUALS=false
NX_UPDATE_MARKET_STATE=false
NX_REFERRALS=false
NX_VOLUME_DISCOUNTS=false
+4
View File
@@ -49,6 +49,10 @@ There are a few different configuration options offered for this app:
| `NX_ETH_WALLET_MNEMONIC` (optional) | The mnemonic to be used to sign transactions with in browser |
| `NX_LOCAL_PROVIDER_URL` (optional) | The local node to use to send transaction to when signing in browser |
## Example configs:
For example configurations, check out our [netlify.toml](./netlify.toml).
## Testing
To run the minimal set of unit tests, run the following:
+4
View File
@@ -0,0 +1,4 @@
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
+9
View File
@@ -69,6 +69,15 @@
"jestConfig": "apps/governance/jest.config.ts"
}
},
"build-netlify": {
"executor": "nx:run-commands",
"options": {
"commands": [
"cp apps/governance/netlify.toml netlify.toml",
"nx build token"
]
}
},
"build-spec": {
"executor": "nx:run-commands",
"outputs": [],
+8 -9
View File
@@ -4,7 +4,7 @@ import { Splash } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet, useEagerConnect } from '@vegaprotocol/wallet';
import { FLAGS, useEnvironment } from '@vegaprotocol/environment';
import { useWeb3React } from '@web3-react/core';
import React, { Suspense } from 'react';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { SplashError } from './components/splash-error';
@@ -164,14 +164,13 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
);
}
const loading = (
<Splash>
<SplashLoader />
</Splash>
);
if (!loaded) {
return loading;
return (
<Splash>
<SplashLoader />
</Splash>
);
}
return <Suspense fallback={loading}>{children}</Suspense>;
return children;
};
+3 -6
View File
@@ -42,7 +42,6 @@ import {
useNodeSwitcherStore,
DocsLinks,
NodeFailure,
AppLoader as Loader,
} from '@vegaprotocol/environment';
import { ENV } from './config';
import type { InMemoryCacheConfig } from '@apollo/client';
@@ -353,11 +352,9 @@ function App() {
useInitializeEnv();
return (
<React.Suspense fallback={<Loader />}>
<NetworkLoader cache={cache}>
<AppContainer />
</NetworkLoader>
</React.Suspense>
<NetworkLoader cache={cache}>
<AppContainer />
</NetworkLoader>
);
}
-1
View File
@@ -1 +0,0 @@
../../../../libs/i18n/src/locales
@@ -10,7 +10,7 @@ import noIcon from '../../images/token-no-icon.png';
import vegaBlack from '../../images/vega_black.png';
import vegaVesting from '../../images/vega_vesting.png';
import { BigNumber } from '../../lib/bignumber';
import { type WalletCardAssetProps } from '../wallet-card';
import type { WalletCardAssetProps } from '../wallet-card';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useContracts } from '../../contexts/contracts/contracts-context';
import * as Schema from '@vegaprotocol/types';
@@ -21,12 +21,12 @@ import {
toBigNum,
} from '@vegaprotocol/utils';
import { useAppState } from '../../contexts/app-state/app-state-context';
import {
DelegationsDocument,
type DelegationsQuery,
type DelegationsQueryVariables,
type WalletDelegationFieldsFragment,
import type {
DelegationsQuery,
DelegationsQueryVariables,
WalletDelegationFieldsFragment,
} from './__generated__/Delegations';
import { DelegationsDocument } from './__generated__/Delegations';
import { isPartyNotFoundError } from '../../lib/party';
export const usePollForDelegations = () => {
@@ -44,7 +44,6 @@ export const usePollForDelegations = () => {
const [delegatedNodes, setDelegatedNodes] = React.useState<
{
nodeId: string;
// eslint-disable-next-line
name: string;
hasStakePending: boolean;
currentEpochStake?: BigNumber;
@@ -114,16 +113,6 @@ export const usePollForDelegations = () => {
isAssetTypeERC20(a.asset) &&
a.asset.source.contractAddress === vegaToken.address;
const isVesting =
a.type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS ||
a.type === Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS;
let icon = noIcon;
if (isVega) {
if (isVesting) icon = vegaVesting;
else icon = vegaBlack;
}
return {
isVega,
name: a.asset.name,
@@ -134,7 +123,14 @@ export const usePollForDelegations = () => {
balance: new BigNumber(
addDecimal(a.balance, a.asset.decimals)
),
image: icon,
image: isVega
? vegaBlack
: a.type ===
Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS ||
a.type ===
Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS
? vegaVesting
: noIcon,
border: isVega,
address: isAssetTypeERC20(a.asset)
? a.asset.source.contractAddress
@@ -11,10 +11,7 @@ import { BigNumber } from '../../lib/bignumber';
import { truncateMiddle } from '../../lib/truncate-middle';
import Routes from '../../routes/routes';
import { BulletHeader } from '../bullet-header';
import type {
WalletCardAssetProps,
WalletCardAssetWithMultipleBalancesProps,
} from '../wallet-card';
import type { WalletCardAssetProps } from '../wallet-card';
import {
WalletCard,
WalletCardActions,
@@ -30,7 +27,6 @@ import { Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
import { toBigNum } from '@vegaprotocol/utils';
import { usePendingBalancesStore } from '../../hooks/use-pending-balances-manager';
import { StakingEventType } from '../../hooks/use-get-association-breakdown';
import omit from 'lodash/omit';
export const VegaWallet = () => {
const { t } = useTranslation();
@@ -103,29 +99,12 @@ const VegaWalletAssetList = ({ accounts }: VegaWalletAssetsListProps) => {
if (!accounts.length) {
return null;
}
const groupedByAsset = accounts.reduce((all, a) => {
const foundIndex = all.findIndex((acc) => acc.assetId === a.assetId);
if (foundIndex > -1) {
const found = all[foundIndex];
all[foundIndex] = {
...found,
balances: [...found.balances, { balance: a.balance, type: a.type }],
};
return all;
}
const acc = {
...omit(a, 'balance', 'type'),
balances: [{ balance: a.balance, type: a.type }],
};
return [...all, acc];
}, [] as WalletCardAssetWithMultipleBalancesProps[]);
return (
<>
<WalletCardHeader>
<BulletHeader tag="h2">{t('assets')}</BulletHeader>
</WalletCardHeader>
{groupedByAsset.map((a, i) => (
{accounts.map((a, i) => (
<WalletCardAsset key={i} {...a} />
))}
</>
@@ -203,7 +182,6 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
subheading={t('Associated')}
symbol="VEGA"
balance={currentStakeAvailable}
allowZeroBalance={true}
/>
{totalPending.eq(0) ? null : (
<>
@@ -214,7 +192,6 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
subheading={t('Pending association')}
symbol="VEGA"
balance={totalPending}
allowZeroBalance={true}
/>
<WalletCardAsset
image={vegaWhite}
@@ -223,7 +200,6 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
subheading={t('Total associated after pending')}
symbol="VEGA"
balance={pendingStakeAmount}
allowZeroBalance={true}
/>
</>
)}
@@ -103,7 +103,7 @@ export const WalletCardActions = ({
return <div className="flex justify-end gap-2 mb-4">{children}</div>;
};
export type WalletCardAssetProps = {
export interface WalletCardAssetProps {
image: string;
name: string;
symbol: string;
@@ -113,61 +113,42 @@ export type WalletCardAssetProps = {
border?: boolean;
subheading?: string;
type?: Schema.AccountType;
allowZeroBalance?: boolean;
};
export type WalletCardAssetWithMultipleBalancesProps = Omit<
WalletCardAssetProps,
'balance' | 'type'
> & {
balances: { balance: BigNumber; type?: Schema.AccountType }[];
};
}
export const WalletCardAsset = ({
image,
name,
symbol,
balance,
decimals,
assetId,
border,
subheading,
allowZeroBalance = false,
...props
}: WalletCardAssetProps | WalletCardAssetWithMultipleBalancesProps) => {
const balance = 'balance' in props ? props.balance : undefined;
const type = 'type' in props ? props.type : undefined;
const balances =
'balances' in props
? props.balances
: balance
? [{ balance, type }]
: undefined;
type,
}: WalletCardAssetProps) => {
const [integers, decimalsPlaces, separator] = useNumberParts(
balance,
decimals
);
const { t } = useTranslation();
const consoleLink = useLinks(DApp.Console);
const transferAssetLink = (assetId: string) =>
consoleLink(CONSOLE_TRANSFER_ASSET.replace(':assetId', assetId));
const { param: baseRate } = useNetworkParam('rewards_vesting_baseRate');
const values =
balances &&
balances.length > 0 &&
balances
.filter((b) => allowZeroBalance || !b.balance.isZero())
.sort((a, b) => {
const order = [
Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS,
Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
Schema.AccountType.ACCOUNT_TYPE_GENERAL,
undefined,
];
return order.indexOf(a.type) - order.indexOf(b.type);
})
.map(({ balance, type }, i) => (
<CurrencyValue
key={i}
balance={balance}
decimals={decimals}
type={type}
assetId={assetId}
/>
));
const isRedeemable =
type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS && assetId;
if (!values || values.length === 0) return;
const accountTypeTooltip = useMemo(() => {
if (type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS) {
return t('VestedRewardsTooltip');
}
if (type === Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS && baseRate) {
return t('VestingRewardsTooltip', { baseRate });
}
return null;
}, [baseRate, t, type]);
return (
<div className="flex flex-nowrap gap-2 mt-2 mb-4">
@@ -188,92 +169,35 @@ export const WalletCardAsset = ({
{subheading || symbol}
</div>
</div>
{values}
</div>
</div>
);
};
const useAccountTypeTooltip = (type?: Schema.AccountType) => {
const { t } = useTranslation();
const { param: baseRate } = useNetworkParam('rewards_vesting_baseRate');
const accountTypeTooltip = useMemo(() => {
if (type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS) {
return t('VestedRewardsTooltip');
}
if (type === Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS && baseRate) {
return t('VestingRewardsTooltip', { baseRate });
}
return null;
}, [baseRate, t, type]);
return accountTypeTooltip;
};
const CurrencyValue = ({
balance,
decimals,
type,
assetId,
}: {
balance: BigNumber;
decimals: number;
type?: Schema.AccountType;
assetId?: string;
}) => {
const { t } = useTranslation();
const consoleLink = useLinks(DApp.Console);
const transferAssetLink = (assetId: string) =>
consoleLink(CONSOLE_TRANSFER_ASSET.replace(':assetId', assetId));
const [integers, decimalsPlaces, separator] = useNumberParts(
balance,
decimals
);
const accountTypeTooltip = useAccountTypeTooltip(type);
const accountType = type && (
<Tooltip description={accountTypeTooltip}>
<span className="px-2 py-1 leading-none text-xs bg-vega-cdark-700 rounded">
{Schema.AccountTypeMapping[type]}
</span>
</Tooltip>
);
const isRedeemable =
type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS && assetId;
const redeemBtn = isRedeemable ? (
<Tooltip description={t('RedeemRewardsTooltip')}>
<AnchorButton
variant="primary"
size="xs"
href={transferAssetLink(assetId)}
target="_blank"
className="px-2 py-1 leading-none text-xs bg-vega-yellow text-black rounded"
>
{t('Redeem')}
</AnchorButton>
</Tooltip>
) : null;
return (
<div
className="basis-full font-mono mb-1"
data-account-type={type?.toLowerCase() || 'unspecified'}
data-testid="currency-value"
>
{type && (
<div data-type className="flex gap-1">
{accountType}
{redeemBtn}
{type ? (
<div className="mb-[2px] flex gap-2 items-baseline">
<Tooltip description={accountTypeTooltip}>
<span className="px-2 py-1 leading-none text-xs bg-vega-cdark-700 rounded">
{Schema.AccountTypeMapping[type]}
</span>
</Tooltip>
{isRedeemable ? (
<Tooltip description={t('RedeemRewardsTooltip')}>
<AnchorButton
variant="primary"
size="xs"
href={transferAssetLink(assetId)}
target="_blank"
className="px-2 py-1 leading-none text-xs bg-vega-yellow text-black rounded"
>
{t('Redeem')}
</AnchorButton>
</Tooltip>
) : null}
</div>
) : null}
<div className="basis-full font-mono" data-testid="currency-value">
<span>
{integers}
{separator}
</span>
<span className="text-neutral-400">{decimalsPlaces}</span>
</div>
)}
<div data-value>
<span>
{integers}
{separator}
</span>
<span className="text-neutral-400">{decimalsPlaces}</span>
</div>
</div>
);
@@ -9,7 +9,7 @@ import { useWeb3React } from '@web3-react/core';
import React from 'react';
import { SplashLoader } from '../../components/splash-loader';
import { type ContractsContextShape } from './contracts-context';
import type { ContractsContextShape } from './contracts-context';
import { ContractsContext } from './contracts-context';
import { createDefaultProvider } from '../../lib/web3-connectors';
import { useEthereumConfig } from '@vegaprotocol/web3';
+14 -27
View File
@@ -1,42 +1,29 @@
import type { Module } from 'i18next';
import i18n from 'i18next';
import HttpBackend from 'i18next-http-backend';
import LocizeBackend from 'i18next-locize-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';
const isInDev = process.env.NODE_ENV === 'development';
const useLocize = isInDev && !!process.env.NX_USE_LOCIZE;
const backend = useLocize
? {
projectId: '96ac1231-4bdd-455a-b9d7-f5322a2e7430',
apiKey: process.env.NX_LOCIZE_API_KEY,
referenceLng: 'en',
}
: {
loadPath: '/assets/locales/{{lng}}/{{ns}}.json',
};
const Backend: Module = useLocize ? LocizeBackend : HttpBackend;
import dev from './translations/dev.json';
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
lng: 'en',
// we init with resources
resources: {
en: {
translations: {
...dev,
},
},
},
lng: undefined,
fallbackLng: 'en',
supportedLngs: ['en'],
load: 'languageOnly',
debug: isInDev,
debug: true,
// have a common namespace used around the full app
ns: ['governance'],
defaultNS: 'governance',
ns: ['translations'],
defaultNS: 'translations',
keySeparator: false, // we use content as keys
nsSeparator: false,
backend,
saveMissing: useLocize && !!process.env.NX_LOCIZE_API_KEY,
interpolation: {
escapeValue: false,
},
@@ -189,6 +189,7 @@ const GovernanceHome = ({ name }: RouteChildProps) => {
includeNewMarketProductFields: !!FLAGS.PRODUCT_PERPETUALS,
includeUpdateMarketStates: !!FLAGS.UPDATE_MARKET_STATE,
includeUpdateReferralPrograms: !!FLAGS.REFERRALS,
includeUpdateVolumeDiscountPrograms: !!FLAGS.VOLUME_DISCOUNTS,
},
});
@@ -1,4 +1,4 @@
import { type CollateralBridge } from '@vegaprotocol/smart-contracts';
import type { CollateralBridge } from '@vegaprotocol/smart-contracts';
import * as Schema from '@vegaprotocol/types';
import { Button } from '@vegaprotocol/ui-toolkit';
import { useBridgeContract, useEthereumTransaction } from '@vegaprotocol/web3';
@@ -88,7 +88,7 @@ export const ListAsset = ({
assetData.erc20ListAssetBundle;
return (
<div className="mb-8">
<h3 className="mb-2 text-xl">{t('ListAsset')}</h3>
<h3 className="text-xl mb-2">{t('ListAsset')}</h3>
<p className="pr-8">{t('ListAssetDescription')}</p>
<EthWalletContainer>
<Button
@@ -78,7 +78,7 @@ export const ProposalVolumeDiscountProgramDetails = ({
{t('BenefitTiers')}
</h3>
<KeyValueTable>
{[...benefitTiers]
{benefitTiers
.sort(
(a, b) =>
Number(a.minimumRunningNotionalTakerVolume) -
@@ -4,7 +4,7 @@ import { VoteValue } from '@vegaprotocol/types';
import { useEffect, useState } from 'react';
import { useUserVoteQuery } from './__generated__/Vote';
import { removePaginationWrapper } from '@vegaprotocol/utils';
import { type FinalizedVote } from '@vegaprotocol/proposals';
import type { FinalizedVote } from '@vegaprotocol/proposals';
export enum VoteState {
NotCast = 'NotCast',
@@ -84,6 +84,7 @@ query Proposal(
$includeNewMarketProductField: Boolean!
$includeUpdateMarketState: Boolean!
$includeUpdateReferralProgram: Boolean!
$includeUpdateVolumeDiscountProgram: Boolean!
) {
proposal(id: $proposalId) {
id
@@ -103,6 +104,7 @@ query Proposal(
...UpdateMarketState @include(if: $includeUpdateMarketState)
...UpdateReferralProgram @include(if: $includeUpdateReferralProgram)
...UpdateVolumeDiscountProgram
@include(if: $includeUpdateVolumeDiscountProgram)
terms {
closingDatetime
enactmentDatetime
@@ -16,6 +16,7 @@ export type ProposalQueryVariables = Types.Exact<{
includeNewMarketProductField: Types.Scalars['Boolean'];
includeUpdateMarketState: Types.Scalars['Boolean'];
includeUpdateReferralProgram: Types.Scalars['Boolean'];
includeUpdateVolumeDiscountProgram: Types.Scalars['Boolean'];
}>;
@@ -107,7 +108,7 @@ export const UpdateVolumeDiscountProgramFragmentDoc = gql`
}
`;
export const ProposalDocument = gql`
query Proposal($proposalId: ID!, $includeNewMarketProductField: Boolean!, $includeUpdateMarketState: Boolean!, $includeUpdateReferralProgram: Boolean!) {
query Proposal($proposalId: ID!, $includeNewMarketProductField: Boolean!, $includeUpdateMarketState: Boolean!, $includeUpdateReferralProgram: Boolean!, $includeUpdateVolumeDiscountProgram: Boolean!) {
proposal(id: $proposalId) {
id
rationale {
@@ -125,7 +126,7 @@ export const ProposalDocument = gql`
...NewMarketProductField @include(if: $includeNewMarketProductField)
...UpdateMarketState @include(if: $includeUpdateMarketState)
...UpdateReferralProgram @include(if: $includeUpdateReferralProgram)
...UpdateVolumeDiscountProgram
...UpdateVolumeDiscountProgram @include(if: $includeUpdateVolumeDiscountProgram)
terms {
closingDatetime
enactmentDatetime
@@ -433,6 +434,7 @@ ${UpdateVolumeDiscountProgramFragmentDoc}`;
* includeNewMarketProductField: // value for 'includeNewMarketProductField'
* includeUpdateMarketState: // value for 'includeUpdateMarketState'
* includeUpdateReferralProgram: // value for 'includeUpdateReferralProgram'
* includeUpdateVolumeDiscountProgram: // value for 'includeUpdateVolumeDiscountProgram'
* },
* });
*/
@@ -62,6 +62,7 @@ export const ProposalContainer = () => {
includeNewMarketProductField: !!FLAGS.PRODUCT_PERPETUALS,
includeUpdateMarketState: !!FLAGS.UPDATE_MARKET_STATE,
includeUpdateReferralProgram: !!FLAGS.REFERRALS,
includeUpdateVolumeDiscountProgram: !!FLAGS.VOLUME_DISCOUNTS,
},
skip: !params.proposalId,
});
@@ -164,6 +164,7 @@ query Proposals(
$includeNewMarketProductFields: Boolean!
$includeUpdateMarketStates: Boolean!
$includeUpdateReferralPrograms: Boolean!
$includeUpdateVolumeDiscountPrograms: Boolean!
) {
proposalsConnection {
edges {
@@ -173,6 +174,7 @@ query Proposals(
...UpdateMarketStates @include(if: $includeUpdateMarketStates)
...UpdateReferralPrograms @include(if: $includeUpdateReferralPrograms)
...UpdateVolumeDiscountPrograms
@include(if: $includeUpdateVolumeDiscountPrograms)
}
}
}
@@ -17,6 +17,7 @@ export type ProposalsQueryVariables = Types.Exact<{
includeNewMarketProductFields: Types.Scalars['Boolean'];
includeUpdateMarketStates: Types.Scalars['Boolean'];
includeUpdateReferralPrograms: Types.Scalars['Boolean'];
includeUpdateVolumeDiscountPrograms: Types.Scalars['Boolean'];
}>;
@@ -190,7 +191,7 @@ export const ProposalFieldsFragmentDoc = gql`
}
`;
export const ProposalsDocument = gql`
query Proposals($includeNewMarketProductFields: Boolean!, $includeUpdateMarketStates: Boolean!, $includeUpdateReferralPrograms: Boolean!) {
query Proposals($includeNewMarketProductFields: Boolean!, $includeUpdateMarketStates: Boolean!, $includeUpdateReferralPrograms: Boolean!, $includeUpdateVolumeDiscountPrograms: Boolean!) {
proposalsConnection {
edges {
node {
@@ -198,7 +199,7 @@ export const ProposalsDocument = gql`
...NewMarketProductFields @include(if: $includeNewMarketProductFields)
...UpdateMarketStates @include(if: $includeUpdateMarketStates)
...UpdateReferralPrograms @include(if: $includeUpdateReferralPrograms)
...UpdateVolumeDiscountPrograms
...UpdateVolumeDiscountPrograms @include(if: $includeUpdateVolumeDiscountPrograms)
}
}
}
@@ -224,6 +225,7 @@ ${UpdateVolumeDiscountProgramsFragmentDoc}`;
* includeNewMarketProductFields: // value for 'includeNewMarketProductFields'
* includeUpdateMarketStates: // value for 'includeUpdateMarketStates'
* includeUpdateReferralPrograms: // value for 'includeUpdateReferralPrograms'
* includeUpdateVolumeDiscountPrograms: // value for 'includeUpdateVolumeDiscountPrograms'
* },
* });
*/
@@ -5,17 +5,15 @@ import { useTranslation } from 'react-i18next';
import { SplashLoader } from '../../../components/splash-loader';
import { ProposalsList } from '../components/proposals-list';
import { useProposalsQuery } from './__generated__/Proposals';
import { getNodes, removePaginationWrapper } from '@vegaprotocol/utils';
import {
ProposalState,
ProtocolUpgradeProposalStatus,
} from '@vegaprotocol/types';
import { type NodeConnection, type NodeEdge } from '@vegaprotocol/utils';
import {
useProposalsQuery,
type ProposalFieldsFragment,
} from './__generated__/Proposals';
import { type ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
import type { NodeConnection, NodeEdge } from '@vegaprotocol/utils';
import type { ProposalFieldsFragment } from './__generated__/Proposals';
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
import { useProtocolUpgradeProposalsQuery } from '@vegaprotocol/proposals';
import { FLAGS } from '@vegaprotocol/environment';
@@ -52,6 +50,7 @@ export const ProposalsContainer = () => {
includeNewMarketProductFields: !!FLAGS.PRODUCT_PERPETUALS,
includeUpdateMarketStates: !!FLAGS.UPDATE_MARKET_STATE,
includeUpdateReferralPrograms: !!FLAGS.REFERRALS,
includeUpdateVolumeDiscountPrograms: !!FLAGS.VOLUME_DISCOUNTS,
},
});
@@ -42,6 +42,7 @@ export const RejectedProposalsContainer = () => {
includeNewMarketProductFields: !!FLAGS.PRODUCT_PERPETUALS,
includeUpdateMarketStates: !!FLAGS.UPDATE_MARKET_STATE,
includeUpdateReferralPrograms: !!FLAGS.REFERRALS,
includeUpdateVolumeDiscountPrograms: !!FLAGS.VOLUME_DISCOUNTS,
},
});
@@ -5,9 +5,9 @@ import * as faker from 'faker';
import isArray from 'lodash/isArray';
import mergeWith from 'lodash/mergeWith';
import { type PartialDeep } from 'type-fest';
import { type ProposalQuery } from '../proposal/__generated__/Proposal';
import { type ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
import type { PartialDeep } from 'type-fest';
import type { ProposalQuery } from '../proposal/__generated__/Proposal';
import type { ProtocolUpgradeProposalFieldsFragment } from '@vegaprotocol/proposals';
export function generateProtocolUpgradeProposal(
override: PartialDeep<ProtocolUpgradeProposalFieldsFragment> = {}
@@ -22,13 +22,11 @@ interface UserBalances {
balance: BigNumber;
}
type Params = { address: string };
export const RedemptionInformation = () => {
const { t } = useTranslation();
const navigate = useNavigate();
const tranches = useTranches((state) => state.tranches);
const { address } = useParams<Params>();
const { address } = useParams<{ address: string }>();
const [userBalances, setUserBalances] = useState<null | UserBalances>();
const getUsersBalances = useGetUserBalances(address);
useEffect(() => {
@@ -86,7 +84,7 @@ export const RedemptionInformation = () => {
i18nKey="noVestingTokens"
components={{
tranchesLink: (
<Link className="text-white underline" to={Routes.SUPPLY} />
<Link className="underline text-white" to={Routes.SUPPLY} />
),
}}
/>
@@ -162,7 +160,7 @@ export const RedemptionInformation = () => {
intent={Intent.Warning}
>
<p>{t('Find out more about Staking.')}</p>
<Link to={Routes.VALIDATORS} className="text-white underline">
<Link to={Routes.VALIDATORS} className="underline text-white">
{t('Stake VEGA tokens')}
</Link>
</Callout>
@@ -21,10 +21,9 @@ import RoutesConfig from '../routes';
interface FormFields {
address: string;
}
type Params = { address: string };
const RedemptionRouter = () => {
const { address } = useParams<Params>();
const { address } = useParams<{ address: string }>();
const navigate = useNavigate();
const { t } = useTranslation();
const validatePubkey = useCallback(
@@ -90,7 +89,7 @@ const RedemptionRouter = () => {
{t('View connected Eth Wallet')}
</Button>
)}
<p className="flex justify-center py-4">{t('OR')}</p>
<p className="py-4 flex justify-center">{t('OR')}</p>
<form
onSubmit={handleSubmit(onSubmit)}
data-testid="view-connector-form"
@@ -21,8 +21,6 @@ import { EthConnectPrompt } from '../../../components/eth-connect-prompt';
import { useUserTrancheBalances } from '../hooks';
import { useAppState } from '../../../contexts/app-state/app-state-context';
type Params = { id: string };
export const RedeemFromTranche = () => {
const { account: address } = useWeb3React();
const { vesting } = useContracts();
@@ -36,7 +34,7 @@ export const RedeemFromTranche = () => {
tranches: state.tranches,
getTranches: state.getTranches,
}));
const { id } = useParams<Params>();
const { id } = useParams<{ id: string }>();
const numberId = Number(id);
const tranche = React.useMemo(
() => tranches?.find(({ tranche_id }) => tranche_id === numberId) || null,
@@ -88,7 +86,7 @@ export const RedeemFromTranche = () => {
i18nKey="noVestingTokens"
components={{
tranchesLink: (
<Link className="text-white underline" to={Routes.SUPPLY} />
<Link className="underline text-white" to={Routes.SUPPLY} />
),
}}
/>
@@ -130,13 +128,13 @@ export const RedeemFromTranche = () => {
components={{
stakingLink: (
<Link
className="text-white underline"
className="underline text-white"
to={Routes.VALIDATORS}
/>
),
governanceLink: (
<Link
className="text-white underline"
className="underline text-white"
to={Routes.PROPOSALS}
/>
),
@@ -11,12 +11,12 @@ import { useTransaction } from '../../../hooks/use-transaction';
import { useAppState } from '../../../contexts/app-state/app-state-context';
import { removeDecimal, removePaginationWrapper } from '@vegaprotocol/utils';
import * as Schema from '@vegaprotocol/types';
import {
PartyStakeLinkingsDocument,
type LinkingsFieldsFragment,
type PartyStakeLinkingsQuery,
type PartyStakeLinkingsQueryVariables,
import type {
LinkingsFieldsFragment,
PartyStakeLinkingsQuery,
PartyStakeLinkingsQueryVariables,
} from './__generated__/PartyStakeLinkings';
import { PartyStakeLinkingsDocument } from './__generated__/PartyStakeLinkings';
export const useAddStake = (
address: string,
@@ -26,9 +26,9 @@ import {
ValidatorRenderer,
VotingPowerRenderer,
} from './shared';
import { type AgGridReact } from 'ag-grid-react';
import { type ColDef, type RowHeightParams } from 'ag-grid-community';
import { type ValidatorsTableProps } from './shared';
import type { AgGridReact } from 'ag-grid-react';
import type { ColDef, RowHeightParams } from 'ag-grid-community';
import type { ValidatorsTableProps } from './shared';
import {
formatNumber,
formatNumberPercentage,
@@ -83,19 +83,19 @@ const TopThirdCellRenderer = (
e.preventDefault();
setHideTopThird(false);
}}
className="grid h-full w-full grid-cols-[60px_1fr] overflow-scroll px-0 py-4 text-center text-sm text-white"
className="grid grid-cols-[60px_1fr] w-full h-full py-4 px-0 text-sm text-white text-center overflow-scroll"
>
<div className="px-3 text-left text-xs">
<div className="px-3 text-xs text-left">
{params?.data?.rankingDisplay}
</div>
<div className="whitespace-normal px-3">
<div className="px-3 whitespace-normal">
<div className="mb-4">
<Button
data-testid="show-all-validators"
rightIcon={
<Icon
name="arrow-right"
className="mr-2 fill-current align-text-top"
className="mr-2 align-text-top fill-current"
/>
}
className="inline-flex items-center"
@@ -22,9 +22,9 @@ import {
PendingStakeRenderer,
VotingPowerRenderer,
} from './shared';
import { type AgGridReact } from 'ag-grid-react';
import { type ColDef } from 'ag-grid-community';
import { type ValidatorsTableProps } from './shared';
import type { AgGridReact } from 'ag-grid-react';
import type { ColDef } from 'ag-grid-community';
import type { ValidatorsTableProps } from './shared';
import {
formatNumber,
formatNumberPercentage,
@@ -28,14 +28,12 @@ interface StakingNodeProps {
previousEpochData?: PreviousEpochQuery;
}
type Params = { node: string };
export const StakingNode = ({ data, previousEpochData }: StakingNodeProps) => {
const { pubKey: vegaKey } = useVegaWallet();
const {
appState: { decimals },
} = useAppState();
const { node } = useParams<Params>();
const { node } = useParams<{ node: string }>();
const { t } = useTranslation();
const { nodeInfo, currentEpoch, delegations } = React.useMemo(
@@ -16,12 +16,10 @@ import Routes from '../routes';
import { TrancheLabel } from './tranche-label';
import { useTranches } from '../../lib/tranches/tranches-store';
type Params = { trancheId: string; address: string };
export const Tranche = () => {
const tranches = useTranches((state) => state.tranches);
const { t } = useTranslation();
const { trancheId } = useParams<Params>();
const { trancheId } = useParams<{ trancheId: string; address: string }>();
const { chainId } = useWeb3React();
const tranche = tranches?.find(
(tranche) => trancheId && parseInt(trancheId) === tranche.tranche_id
@@ -43,7 +41,7 @@ export const Tranche = () => {
}
/>
<div
className="flex justify-between gap-x-4 px-4 py-2"
className="flex justify-between gap-x-4 py-2 px-4"
data-testid="redeemed-tranche-tokens"
>
<span>{t('alreadyRedeemed')}</span>
+10 -4
View File
@@ -3,7 +3,7 @@
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
import { locales } from '@vegaprotocol/i18n';
import dev from './i18n/translations/dev.json';
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import ResizeObserver from 'resize-observer-polyfill';
@@ -12,10 +12,16 @@ import ResizeObserver from 'resize-observer-polyfill';
// en translations
i18n.use(initReactI18next).init({
// we init with resources
resources: locales,
resources: {
en: {
translations: {
...dev,
},
},
},
fallbackLng: 'en',
ns: ['governance'],
defaultNS: 'governance',
ns: ['translations'],
defaultNS: 'translations',
});
global.ResizeObserver = ResizeObserver;
@@ -0,0 +1,4 @@
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
@@ -82,6 +82,15 @@
"jestConfig": "apps/liquidity-provision-dashboard/jest.config.ts"
}
},
"build-netlify": {
"executor": "nx:run-commands",
"options": {
"commands": [
"cp apps/liquidity-provision-dashboard/netlify.toml netlify.toml",
"nx build liquidity-provision-dashboard"
]
}
},
"build-spec": {
"executor": "nx:run-commands",
"outputs": [],
@@ -1,5 +1,5 @@
import { DApp, useLinks } from '@vegaprotocol/environment';
import { type Market } from '@vegaprotocol/liquidity';
import type { Market } from '@vegaprotocol/liquidity';
import {
displayChange,
formatWithAsset,
@@ -12,7 +12,7 @@ import {
toBigNum,
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { type VegaValueFormatterParams } from '@vegaprotocol/datagrid';
import type { VegaValueFormatterParams } from '@vegaprotocol/datagrid';
import { PriceChangeCell } from '@vegaprotocol/datagrid';
import type * as Schema from '@vegaprotocol/types';
import {
@@ -21,10 +21,10 @@ import {
HealthBar,
TooltipCellComponent,
} from '@vegaprotocol/ui-toolkit';
import {
type GetRowIdParams,
type RowClickedEvent,
type ColDef,
import type {
GetRowIdParams,
RowClickedEvent,
ColDef,
} from 'ag-grid-community';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
@@ -253,7 +253,7 @@ export const MarketList = () => {
return (
<AsyncRenderer loading={loading} error={error} data={data}>
<div
className="w-full grow"
className="grow w-full"
style={{ minHeight: 500, overflow: 'hidden' }}
>
<Grid
@@ -60,21 +60,19 @@ const useMarketDetails = (marketId: string | undefined) => {
};
};
type Params = { marketId: string };
export const Detail = () => {
const { marketId } = useParams<Params>();
const { marketId } = useParams<{ marketId: string }>();
const { data, loading, error } = useMarketDetails(marketId);
return (
<AsyncRenderer loading={loading} error={error} data={data}>
<div className="bg-greys-light-100 px-16 pb-12 pt-14">
<div className="mx-auto max-w-screen-xl">
<div className="px-16 pt-14 pb-12 bg-greys-light-100">
<div className="max-w-screen-xl mx-auto">
<Header name={data.name} symbol={data.symbol} />
</div>
</div>
<div className="px-16">
<div className="mx-auto max-w-screen-xl">
<div className="max-w-screen-xl mx-auto">
<div className="py-12">
{marketId && (
<Market
@@ -88,7 +86,7 @@ export const Detail = () => {
)}
</div>
<div>
<h2 className="font-alpha calt mb-4 text-2xl">
<h2 className="font-alpha calt text-2xl mb-4">
{t('Current Liquidity Provision')}
</h2>
<LPProvidersGrid
@@ -1,11 +1,11 @@
import { useCallback, useMemo } from 'react';
import { type GetRowIdParams, type ColDef } from 'ag-grid-community';
import type { GetRowIdParams, ColDef } from 'ag-grid-community';
import { t } from '@vegaprotocol/i18n';
import {
type LiquidityProviderFeeShareFieldsFragment,
type LiquidityProvisionFieldsFragment,
import type {
LiquidityProviderFeeShareFieldsFragment,
LiquidityProvisionFieldsFragment,
} from '@vegaprotocol/liquidity';
import { formatWithAsset } from '@vegaprotocol/liquidity';
@@ -1,9 +1,9 @@
import { useRef, useCallback, useEffect } from 'react';
import { AgGridReact } from 'ag-grid-react';
import {
type AgGridReactProps,
type AgReactUiProps,
type AgGridReact as AgGridReactType,
import type {
AgGridReactProps,
AgReactUiProps,
AgGridReact as AgGridReactType,
} from 'ag-grid-react';
import classNames from 'classnames';
import 'ag-grid-community/styles/ag-grid.css';
@@ -34,7 +34,7 @@ export const Grid = ({ isRowClickable, ...props }: Props) => {
return (
<AgGridReact
className={classNames('ag-theme-alpine font-alpha calt h-full', {
className={classNames('ag-theme-alpine h-full font-alpha calt', {
'row-hover': isRowClickable,
})}
rowHeight={92}
+4
View File
@@ -0,0 +1,4 @@
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
+9
View File
@@ -66,6 +66,15 @@
"jestConfig": "apps/multisig-signer/jest.config.ts"
}
},
"build-netlify": {
"executor": "nx:run-commands",
"options": {
"commands": [
"cp apps/multisig-signer/netlify.toml netlify.toml",
"nx build multisig-signer"
]
}
},
"build-spec": {
"executor": "nx:run-commands",
"outputs": [],
@@ -11,12 +11,12 @@ import {
Loader,
} from '@vegaprotocol/ui-toolkit';
import { useContracts } from '../../config/contracts/contracts-context';
import { type FormEvent } from 'react';
import {
type AddSignerBundle,
type AddSignerBundleVariables,
import type { FormEvent } from 'react';
import type {
AddSignerBundle,
AddSignerBundleVariables,
} from '../__generated__/AddSignerBundle';
import { type MultisigControl } from '@vegaprotocol/smart-contracts';
import type { MultisigControl } from '@vegaprotocol/smart-contracts';
export const ADD_SIGNER_QUERY = gql`
query AddSignerBundle($nodeId: ID!) {
@@ -11,12 +11,12 @@ import {
Loader,
} from '@vegaprotocol/ui-toolkit';
import { useContracts } from '../../config/contracts/contracts-context';
import { type FormEvent } from 'react';
import {
type RemoveSignerBundle,
type RemoveSignerBundleVariables,
import type { FormEvent } from 'react';
import type {
RemoveSignerBundle,
RemoveSignerBundleVariables,
} from '../__generated__/RemoveSignerBundle';
import { type MultisigControl } from '@vegaprotocol/smart-contracts';
import type { MultisigControl } from '@vegaprotocol/smart-contracts';
const REMOVE_SIGNER_QUERY = gql`
query RemoveSignerBundle($nodeId: ID!) {
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import { MultisigControl } from '@vegaprotocol/smart-contracts';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { type ContractsContextShape } from './contracts-context';
import type { ContractsContextShape } from './contracts-context';
import { ContractsContext } from './contracts-context';
import { useEthereumConfig } from '@vegaprotocol/web3';
import { useEnvironment } from '@vegaprotocol/environment';
+4
View File
@@ -0,0 +1,4 @@
[[headers]]
for = "/*"
[headers.values]
Access-Control-Allow-Origin = "*"
+9
View File
@@ -46,6 +46,15 @@
"buildTarget": "static:build:production"
}
}
},
"build-netlify": {
"executor": "nx:run-commands",
"options": {
"commands": [
"cp apps/static/netlify.toml netlify.toml",
"nx build static"
]
}
}
}
}
@@ -1,6 +1,23 @@
import { removeDecimal } from '@vegaprotocol/cypress';
import * as Schema from '@vegaprotocol/types';
import {
OrderStatusMapping,
OrderTypeMapping,
Side,
} from '@vegaprotocol/types';
import { isBefore, isAfter, addSeconds, subSeconds } from 'date-fns';
import { createOrder } from '../support/create-order';
import { connectEthereumWallet } from '../support/ethereum-wallet';
import { selectAsset } from '../support/helpers';
const orderSize = 'size';
const orderType = 'type';
const orderStatus = 'status';
const orderRemaining = 'remaining';
const orderPrice = 'price';
const orderTimeInForce = 'timeInForce';
const orderUpdatedAt = 'updatedAt';
const assetSelectField = 'select[name="asset"]';
const amountField = 'input[name="amount"]';
const txTimeout = Cypress.env('txTimeout');
const sepoliaUrl = Cypress.env('ETHERSCAN_URL');
@@ -8,10 +25,18 @@ const btcName = 0;
const vegaName = 4;
const btcSymbol = 'tBTC';
const vegaSymbol = 'VEGA';
const usdcSymbol = 'fUSDC';
const toastContent = 'toast-content';
const openOrdersTab = 'Open';
const depositsTab = 'Deposits';
const collateralTab = 'Collateral';
const toastCloseBtn = 'toast-close';
const price = '390';
const size = '0.0005';
const newPrice = '200';
const completeWithdrawalBtn = 'complete-withdrawal';
const submitTransferBtn = '[type="submit"]';
const transferForm = 'transfer-form';
const depositSubmit = 'deposit-submit';
const approveSubmit = 'approve-submit';
const dialogContent = 'dialog-content';
@@ -91,6 +116,33 @@ describe('capsule - without MultiSign', { tags: '@slow' }, () => {
});
});
it('can key to key transfers', function () {
// 1003-TRAN-023
// 1003-TRAN-006
cy.get('[data-testid="pathname-/portfolio"]').should('exist');
cy.getByTestId(collateralTab).click();
cy.getByTestId('open-transfer').eq(1).click();
cy.getByTestId('transfer-form').should('be.visible');
cy.getByTestId('transfer-form').find('[name="toAddress"]').select(1);
cy.get('select option')
.contains('BTC')
.invoke('index')
.then((index) => {
cy.get(assetSelectField).select(index, { force: true });
});
cy.getByTestId(transferForm)
.find(amountField)
.focus()
.type('1', { delay: 100 });
cy.getByTestId(transferForm).find(submitTransferBtn).click();
cy.getByTestId(toastContent).should(
'contain.text',
'Transfer completeYour transaction has been confirmed View in block explorerTransferTo 7f9cf0…c255351.00 tBTC'
);
cy.getByTestId(toastCloseBtn).click();
});
it('can not withdrawal because of no MultiSign', function () {
// 1002-WITH-022
// 1002-WITH-023
@@ -135,6 +187,143 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
cy.setVegaWallet();
});
it('shows node health', function () {
// 0006-NETW-010
const regex = /^Operational\d+$/;
const market = this.market;
cy.visit(`/#/markets/${market.id}`);
cy.getByTestId('node-health-trigger').realHover();
cy.getByTestId('node-health')
.children()
.first()
.invoke('text')
.should('match', regex);
cy.getByTestId('node-health')
.children()
.eq(1)
.should('contain.text', new URL(Cypress.env('VEGA_URL')).hostname);
});
it('can place and receive an order', function () {
const market = this.market;
cy.visit(`/#/markets/${market.id}`);
const order = {
marketId: market.id,
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
size: size,
price: price,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
};
const rawPrice = removeDecimal(order.price, market.decimalPlaces);
cy.getByTestId(toastCloseBtn, txTimeout).click();
cy.getByTestId('Collateral').click();
cy.get('[col-id="asset.symbol"]', txTimeout).should(
'contain.text',
usdcSymbol
);
createOrder(order);
cy.getByTestId(toastContent).should(
'contain.text',
`Order submittedYour transaction has been confirmed View in block explorerSubmit order - activeTEST.24h+${order.size} @ ${order.price}.00 ${usdcSymbol}`,
{ matchCase: false }
);
cy.getByTestId(toastCloseBtn).click();
// orderbook cells are keyed by price level
cy.getByTestId('tab-orderbook')
.get(`[data-testid="price-${rawPrice}"]`)
.should('contain.text', order.price)
.get(`[data-testid="bid-vol-${rawPrice}"]`)
.should('contain.text', order.size);
cy.getByTestId(openOrdersTab).click();
cy.getByTestId('tab-open-orders').within(() => {
cy.get('.ag-center-cols-container')
.children()
.first()
.within(() => {
cy.get(`[col-id='${orderSize}']`).should(
'contain.text',
order.side === Side.SIDE_BUY ? '+' : '-' + order.size
);
cy.get(`[col-id='${orderType}']`).should(
'contain.text',
OrderTypeMapping[order.type]
);
cy.get(`[col-id='${orderStatus}']`).should(
'contain.text',
OrderStatusMapping.STATUS_ACTIVE
);
cy.get(`[col-id='${orderRemaining}']`).should('contain.text', '0.00');
cy.get(`[col-id='${orderPrice}']`).then(($price) => {
expect(parseFloat($price.text())).to.equal(parseFloat(order.price));
});
cy.get(`[col-id='${orderTimeInForce}']`).should(
'contain.text',
'GTC'
);
checkIfDataAndTimeOfCreationAndUpdateIsEqual(orderUpdatedAt);
});
});
});
it('can edit order', function () {
const market = this.market;
cy.visit(`/#/markets/${market.id}`);
cy.getByTestId(toastCloseBtn, txTimeout).click();
cy.getByTestId(openOrdersTab).click();
cy.getByTestId('edit').first().click();
cy.getByTestId('dialog-title').should('contain.text', 'Edit order');
cy.get('#limitPrice').focus().clear().type(newPrice);
cy.getByTestId('edit-order').find('[type="submit"]').click();
cy.getByTestId(toastContent).should(
'contain.text',
`Order submittedYour transaction has been confirmed View in block explorerEdit order - activeTEST.24h+${size} @ ${price}.00 ${usdcSymbol}+${size} @ ${newPrice}.00 ${usdcSymbol}`,
{ matchCase: false }
);
cy.getByTestId(toastCloseBtn).click({ multiple: true });
cy.getByTestId(openOrdersTab).click();
cy.get('.ag-center-cols-container')
.children()
.first()
.within(() => {
cy.get(`[col-id='${orderPrice}']`).then(($price) => {
expect(parseFloat($price.text())).to.equal(parseFloat(newPrice));
});
checkIfDataAndTimeOfCreationAndUpdateIsEqual(orderUpdatedAt);
});
});
it('can cancel order', function () {
const market = this.market;
cy.visit(`/#/markets/${market.id}`);
cy.getByTestId(toastCloseBtn, txTimeout).click();
cy.getByTestId(openOrdersTab).click();
cy.getByTestId('cancel').first().click();
cy.getByTestId(toastContent).should(
'contain.text',
`Order cancelledYour transaction has been confirmed View in block explorerCancel order - cancelledTEST.24h+${size} @ ${newPrice}.00 ${usdcSymbol}`,
{ matchCase: false }
);
cy.getByTestId(toastCloseBtn).click({ multiple: true });
cy.getByTestId('Closed').click();
cy.getByTestId('tab-closed-orders')
.get('.ag-center-cols-container')
.children()
.first()
.get(`[col-id='${orderStatus}']`, txTimeout)
.should('contain.text', OrderStatusMapping.STATUS_CANCELLED);
});
it('can withdrawal', function () {
// 1002-WITH-0014
// 1002-WITH-006
@@ -335,3 +524,22 @@ describe('capsule', { tags: '@slow', testIsolation: true }, () => {
});
});
});
function checkIfDataAndTimeOfCreationAndUpdateIsEqual(date: string) {
cy.get(`[col-id='${date}'] .ag-cell-wrapper`)
.children('span')
.children('span')
.invoke('data', 'value')
.then(($dateTime) => {
// allow a date 5 seconds either side to allow for
// unexpected latency
const minBefore = subSeconds(new Date(), 5);
const maxAfter = addSeconds(new Date(), 5);
// eslint-disable-next-line no-console
console.log(maxAfter);
const date = new Date($dateTime.toString());
expect(isAfter(date, minBefore) && isBefore(date, maxAfter)).to.equal(
true
);
});
}
@@ -0,0 +1,72 @@
const dialogContent = 'dialog-content';
const nodeHealth = 'node-health';
const nodeHealthTrigger = 'node-health-trigger';
describe('home', { tags: '@regression' }, () => {
before(() => {
cy.setOnBoardingViewed();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/');
});
describe('node health', () => {
it('shows current block height', () => {
// 0006-NETW-004
// 0006-NETW-008
// 0006-NETW-009
cy.getByTestId(nodeHealthTrigger).realHover();
cy.getByTestId(nodeHealth)
.children()
.first()
.should('contain.text', 'Operational', {
timeout: 10000,
})
.should('contain.text', '100'); // all mocked queries have x-block-height header set to 100
cy.getByTestId(nodeHealth)
.children()
.eq(1)
.should('contain.text', new URL(Cypress.env('VEGA_URL')).hostname);
});
it('shows node switcher details', () => {
// 0006-NETW-012
// 0006-NETW-013
// 0006-NETW-014
// 0006-NETW-015
// 0006-NETW-016
cy.getByTestId(nodeHealthTrigger).click();
cy.getByTestId(dialogContent).should('contain.text', 'Connected node');
cy.getByTestId(dialogContent).should(
'contain.text',
'This app will only work on CUSTOM. Select a node to connect to.'
);
cy.getByTestId('node')
.first()
.should('contain.text', new URL(Cypress.env('VEGA_URL')).origin)
.next()
.should('contain.text', 'Response time')
.next()
.should('contain.text', 'Block')
.next()
.should('contain.text', 'Subscription');
cy.getByTestId('custom-row').should('contain.text', 'Other');
cy.getByTestId('dialog-close').click();
});
it('switch to other node', () => {
// 0006-NETW-017
// 0006-NETW-018
// 0006-NETW-019
// 0006-NETW-020
cy.getByTestId(nodeHealthTrigger).click();
cy.getByTestId('connect').should('be.disabled');
cy.getByTestId('node-url-custom').click({ force: true });
cy.getByTestId('connect').should('be.disabled');
cy.get("input[placeholder='https://']")
.focus()
.type(new URL(Cypress.env('VEGA_URL')).origin + '/graphql');
cy.getByTestId('connect').click();
});
});
});
@@ -0,0 +1,87 @@
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import {
accountsQuery,
amendGeneralAccountBalance,
amendMarginAccountBalance,
} from '@vegaprotocol/mock';
describe.skip(
'account validation',
{ tags: '@regression', testIsolation: true },
() => {
describe('zero balance error', () => {
beforeEach(() => {
cy.setVegaWallet();
cy.mockTradingPage();
let accounts = accountsQuery();
accounts = amendMarginAccountBalance(accounts, 'market-0', '1000');
accounts = amendGeneralAccountBalance(accounts, 'market-0', '0');
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Accounts', accounts);
});
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
it('should show an error if your balance is zero', () => {
const accounts = accountsQuery();
amendMarginAccountBalance(accounts, 'market-0', '0');
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Accounts', accounts);
});
// 7002-SORD-060
cy.getByTestId('place-order').should('be.enabled');
// 7002-SORD-003
cy.getByTestId('deal-ticket-error-message-zero-balance').should(
'have.text',
'You need ' +
'tDAI' +
' in your wallet to trade in this market. See all your collateral.Make a deposit'
);
cy.getByTestId('deal-ticket-deposit-dialog-button').should('exist');
});
});
describe('not enough balance warning', () => {
beforeEach(() => {
cy.setVegaWallet();
cy.mockTradingPage();
let accounts = accountsQuery();
accounts = amendMarginAccountBalance(accounts, 'market-0', '1000');
accounts = amendGeneralAccountBalance(accounts, 'market-0', '1');
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Accounts', accounts);
});
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
cy.get('[data-testid="deal-ticket-form"]').then(($form) => {
if (!$form.length) {
cy.getByTestId('Order').click();
}
});
});
it('should display info and button for deposit', () => {
// 7002-SORD-003
// warning should show immediately
cy.getByTestId('deal-ticket-warning-margin').should(
'contain.text',
'You may not have enough margin available to open this position'
);
cy.getByTestId('deal-ticket-warning-margin').should(
'contain.text',
'You may not have enough margin available to open this position. 5.00 tDAI is currently required. You have only 0.01001 tDAI available.'
);
cy.getByTestId('deal-ticket-deposit-dialog-button').click();
cy.getByTestId('sidebar-content')
.find('h2')
.eq(0)
.should('have.text', 'Deposit');
});
});
}
);
@@ -0,0 +1,87 @@
import * as Schema from '@vegaprotocol/types';
import { testOrderSubmission } from '../support/order-validation';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
const displayTomorrow = () => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
return tomorrow.toISOString().substring(0, 16);
};
describe(
'must submit order for market in batch auction',
{ tags: '@regression' },
() => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('successfully places limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '200',
};
createOrder(order);
testOrderSubmission(order, { price: '20000000' });
});
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '50000',
};
createOrder(order);
testOrderSubmission(order, { price: '5000000000' });
});
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
postOnly: false,
reduceOnly: false,
price: '1.00',
expiresAt: displayTomorrow(),
};
createOrder(order);
testOrderSubmission(order, {
price: '100000',
postOnly: false,
reduceOnly: false,
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
});
});
}
);
@@ -0,0 +1,85 @@
import * as Schema from '@vegaprotocol/types';
import { testOrderSubmission } from '../support/order-validation';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
const displayTomorrow = () => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
return tomorrow.toISOString().substring(0, 16);
};
describe(
'must submit order for market in monitoring auction',
{ tags: '@regression' },
() => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('successfully places limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '200',
};
createOrder(order);
testOrderSubmission(order, { price: '20000000' });
});
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
price: '50000',
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order, { price: '5000000000' });
});
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
price: '1.00',
expiresAt: displayTomorrow(),
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order, {
price: '100000',
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
});
});
}
);
@@ -0,0 +1,85 @@
import * as Schema from '@vegaprotocol/types';
import { testOrderSubmission } from '../support/order-validation';
import type { OrderSubmission } from '@vegaprotocol/wallet';
import { createOrder } from '../support/create-order';
const displayTomorrow = () => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
return tomorrow.toISOString().substring(0, 16);
};
describe(
'must submit order for market in opening auction',
{ tags: '@regression' },
() => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY_TARGET_NOT_MET
);
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Markets');
});
beforeEach(() => {
cy.setVegaWallet();
});
it('successfully places limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_BUY,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '200',
};
createOrder(order);
testOrderSubmission(order, { price: '20000000' });
});
it('successfully places limit sell order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
size: '100',
postOnly: false,
reduceOnly: false,
price: '50000',
};
createOrder(order);
testOrderSubmission(order, { price: '5000000000' });
});
it('successfully places GTT limit buy order', () => {
cy.mockVegaWalletTransaction();
const order: OrderSubmission = {
marketId: 'market-0',
type: Schema.OrderType.TYPE_LIMIT,
side: Schema.Side.SIDE_SELL,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
size: '100',
price: '1.00',
expiresAt: displayTomorrow(),
postOnly: false,
reduceOnly: false,
};
createOrder(order);
testOrderSubmission(order, {
price: '100000',
expiresAt:
new Date(order.expiresAt as string).getTime().toString() + '000000',
});
});
}
);
+1 -2
View File
@@ -1,10 +1,9 @@
import { useT } from '../../lib/use-t';
import { t } from '@vegaprotocol/i18n';
import { Links } from '../../lib/links';
import classNames from 'classnames';
import { NavLink, Outlet } from 'react-router-dom';
export const Assets = () => {
const t = useT();
const linkClasses = ({ isActive }: { isActive: boolean }) => {
return classNames('border-b-2 border-transparent', {
'border-vega-yellow': isActive,
@@ -1,3 +1,4 @@
import { t } from '@vegaprotocol/i18n';
import { Intent, TradingAnchorButton } from '@vegaprotocol/ui-toolkit';
import { GetStartedCheckList } from '../../components/welcome-dialog';
import {
@@ -7,10 +8,8 @@ import {
} from '../../components/welcome-dialog/use-get-onboarding-step';
import { Links } from '../../lib/links';
import classNames from 'classnames';
import { useT } from '../../lib/use-t';
export const DepositGetStarted = () => {
const t = useT();
const onboardingDismissed = useOnboardingStore((store) => store.dismissed);
const dismiss = useOnboardingStore((store) => store.dismiss);
const step = useGetOnboardingStep();
@@ -1,7 +1,6 @@
import { useT } from '../../lib/use-t';
import { t } from '@vegaprotocol/i18n';
export const Disclaimer = () => {
const t = useT();
return (
<>
<h1 className="text-4xl uppercase xl:text-5xl font-alpha calt">
@@ -9,44 +8,37 @@ export const Disclaimer = () => {
</h1>
<p className="mt-10 mb-6">
{t(
'DISCLAIMER_P1',
'Vega is a decentralised peer-to-peer protocol that can be used to trade derivatives with cryptoassets. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are supplied to the Vega Protocol and losses due to the fluctuation of prices of assets.'
'Vega is a decentralised peer-to-peer protocol that can be used to trade derivatives with cryptoassets. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are supplied to the Vega Protocol and losses due to the fluctuation of prices of assets.'
)}
</p>
<p className="mb-6">
{t(
'DISCLAIMER_P2',
'Before using the Vega Protocol, review the relevant documentation at docs.vega.xyz to make sure that you understand how it works. Conduct your own due diligence and consult your financial advisor before making any investment decisions.'
'Before using the Vega Protocol, review the relevant documentation at docs.vega.xyz to make sure that you understand how it works. Conduct your own due diligence and consult your financial advisor before making any investment decisions.'
)}
</p>
<p className="mb-6">
{t(
'DISCLAIMER_P3',
'As described in the Vega Protocol core license, the Vega Protocol is provided “as is”, at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.'
'As described in the Vega Protocol core license, the Vega Protocol is provided “as is”, at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.'
)}
</p>
<p className="mb-8">
{t(
'DISCLAIMER_P4',
'No developer or entity involved in creating the Vega Protocol will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Vega Protocol, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or legal costs, or loss of profits, cryptoassets, tokens or anything else of value.'
)}
</p>
<p className="mb-8">
{t(
'DISCLAIMER_P5',
'This website is hosted on a decentralised network, the Interplanetary File System (“IPFS”). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers.'
'This website is hosted on a decentralised network, the Interplanetary File System (“IPFS”). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers.'
)}
</p>
<p className="mb-8">
{t(
'DISCLAIMER_P6',
"The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website's content as such. No party recommends that any cryptoasset should be bought, sold, or held by you via this website. No party ensures the accuracy of information listed on this website or holds any responsibility for any missing or wrong information. You understand that you are using any and all information available here at your own risk."
"The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website's content as such. No party recommends that any cryptoasset should be bought, sold, or held by you via this website. No party ensures the accuracy of information listed on this website or holds any responsibility for any missing or wrong information. You understand that you are using any and all information available here at your own risk."
)}
</p>
<p className="mb-8">
{t(
'DISCLAIMER_P7',
'Additionally, just as you can access email protocols such as SMTP through multiple email clients, you can potentially access the Vega Protocol through many web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.'
'Additionally, just as you can access email protocols such as SMTP through multiple email clients, you can potentially access the Vega Protocol through many web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.'
)}
</p>
</>
+1 -2
View File
@@ -1,8 +1,7 @@
import { t } from '@vegaprotocol/i18n';
import { FeesContainer } from '../../components/fees-container';
import { useT } from '../../lib/use-t';
export const Fees = () => {
const t = useT();
return (
<div className="container p-4 mx-auto">
<h1 className="px-4 pb-4 text-2xl">{t('Fees')}</h1>

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