Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17bc4541e9 | ||
|
|
2bd8044a6c | ||
|
|
b3a82fd6f0 |
@@ -64,11 +64,12 @@ jobs:
|
||||
######
|
||||
|
||||
- name: Run Cypress tests
|
||||
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome --env.grepTags="${{ inputs.tags }}"
|
||||
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
|
||||
working-directory: frontend-monorepo
|
||||
env:
|
||||
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
|
||||
CYPRESS_VEGA_WALLET_API_TOKEN: ${{ steps.setup-vega.outputs.token }}
|
||||
CYPRESS_grepTags: ${{ inputs.tags }}
|
||||
|
||||
######
|
||||
## Upload logs
|
||||
|
||||
@@ -8,16 +8,14 @@ jobs:
|
||||
lint_pr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Use Node.js 16
|
||||
id: Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16.14.0
|
||||
- name: Install root dependencies
|
||||
run: yarn install
|
||||
- name: Install commitlint cli and config
|
||||
run: npm install @commitlint/cli @commitlint/config-conventional
|
||||
- name: Create config
|
||||
run: echo "module.exports = {extends:['@commitlint/config-conventional']};" > commitlint.config.js
|
||||
- name: Check PR title
|
||||
run: echo "${{ github.event.pull_request.title }}" | npx commitlint --config ./commitlint.config-ci.js
|
||||
run: echo "${{ github.event.pull_request.title }}" | npx commitlint
|
||||
|
||||
@@ -6,7 +6,7 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_NETWORKS={\"MAINNET"\:\"https://explorer.vega.xyz"\,\"TESTNET\":\"https://explorer.fairground.wtf\"}
|
||||
NX_TENDERMINT_URL=https://tm.sandbox.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.sandbox.vega.xyz/websocket
|
||||
NX_TENDERMINT_URL=https://tm.n01.sandbox.vega.xyz
|
||||
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.sandbox.vega.xyz/websocket
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_VEGA_GOVERNANCE_URL=https://sandbox.token.vega.xyz
|
||||
|
||||
@@ -6,4 +6,3 @@ NX_VEGA_ENV=STAGNET3
|
||||
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
|
||||
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
|
||||
NX_VEGA_GOVERNANCE_URL=https://stagnet3.token.vega.xyz
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases/
|
||||
|
||||
@@ -8,7 +8,6 @@ import { Main } from './components/main';
|
||||
import { TendermintWebsocketProvider } from './contexts/websocket/tendermint-websocket-provider';
|
||||
import type { InMemoryCacheConfig } from '@apollo/client';
|
||||
import { Footer } from './components/footer/footer';
|
||||
import { AnnouncementBanner, ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
function App() {
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
@@ -41,15 +40,6 @@ function App() {
|
||||
return (
|
||||
<TendermintWebsocketProvider>
|
||||
<NetworkLoader cache={cacheConfig}>
|
||||
<AnnouncementBanner>
|
||||
<div className="font-alpha calt uppercase text-center text-lg text-white">
|
||||
<span className="pr-4">The Mainnet sims are live!</span>
|
||||
<ExternalLink href="https://fairground.wtf/">
|
||||
Come help stress test the network
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</AnnouncementBanner>
|
||||
|
||||
<div className={layoutClasses}>
|
||||
<Header menuOpen={menuOpen} setMenuOpen={setMenuOpen} />
|
||||
<Nav menuOpen={menuOpen} />
|
||||
|
||||
@@ -117,7 +117,7 @@ const NestedDataListItem = ({
|
||||
)}
|
||||
</h4>
|
||||
{!hasChildren && (
|
||||
<code className="text-vega-light-100 mb-2 last:mb-0 dark:text-vega-dark-100 break-all">
|
||||
<code className="text-vega-light-400 mb-2 last:mb-0 dark:text-vega-dark-400 break-all">
|
||||
{JSON.stringify(value, null, ' ')}
|
||||
</code>
|
||||
)}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import React from 'react';
|
||||
import { StatusMessage } from '../status-message';
|
||||
|
||||
interface RenderFetchedProps {
|
||||
|
||||
@@ -66,9 +66,7 @@ export const Search = () => {
|
||||
className="text-white"
|
||||
hasError={Boolean(error?.message)}
|
||||
type="text"
|
||||
placeholder={t(
|
||||
'Enter block number, public key or transaction hash'
|
||||
)}
|
||||
placeholder={t('Enter block number, party id or transaction hash')}
|
||||
/>
|
||||
{error?.message && (
|
||||
<div className="bg-white border border-t-0 border-accent absolute top-[100%] flex-1 w-full pb-2 px-2 rounded-b text-black">
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||
import { BlockLink } from '../../links';
|
||||
import { StatusMessage } from '../../status-message';
|
||||
import { ENV } from '../../../config/env';
|
||||
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||
import type { components } from '../../../../types/explorer';
|
||||
|
||||
interface TxDetailsProtocolUpgradeProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
pubKey: string | undefined;
|
||||
blockData: TendermintBlocksResponse | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validator event: Protocol Upgrade proposal
|
||||
*/
|
||||
export const TxDetailsProtocolUpgrade = ({
|
||||
txData,
|
||||
pubKey,
|
||||
blockData,
|
||||
}: TxDetailsProtocolUpgradeProps) => {
|
||||
if (!txData) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
}
|
||||
|
||||
const upgrade: components['schemas']['v1ProtocolUpgradeProposal'] =
|
||||
txData.command.protocolUpgradeProposal;
|
||||
|
||||
if (!upgrade || !upgrade.upgradeBlockHeight || !upgrade.vegaReleaseTag) {
|
||||
return (
|
||||
<StatusMessage>{t('Invalid upgrade proposal format')}</StatusMessage>
|
||||
);
|
||||
}
|
||||
|
||||
const urlBase = ENV.dataSources.vegaRepoUrl;
|
||||
const release = upgrade.vegaReleaseTag;
|
||||
|
||||
return (
|
||||
<TableWithTbody className="mb-8">
|
||||
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Upgrade at block')}</TableCell>
|
||||
<TableCell>
|
||||
<BlockLink height={upgrade.upgradeBlockHeight} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Upgrade to')}</TableCell>
|
||||
<TableCell>
|
||||
<ExternalLink href={`${urlBase}${release}`}>
|
||||
{upgrade.vegaReleaseTag}
|
||||
</ExternalLink>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableWithTbody>
|
||||
);
|
||||
};
|
||||
@@ -19,8 +19,6 @@ import { TxDetailsLiquidityAmendment } from './tx-liquidity-amend';
|
||||
import { TxDetailsLiquidityCancellation } from './tx-liquidity-cancel';
|
||||
import { TxDetailsDataSubmission } from './tx-data-submission';
|
||||
import { TxProposalVote } from './tx-proposal-vote';
|
||||
import { TxDetailsProtocolUpgrade } from './tx-details-protocol-upgrade';
|
||||
import { TxDetailsIssueSignatures } from './tx-issue-signatures';
|
||||
|
||||
interface TxDetailsWrapperProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
@@ -68,14 +66,10 @@ function getTransactionComponent(txData?: BlockExplorerTransactionResult) {
|
||||
|
||||
// These come from https://github.com/vegaprotocol/vega/blob/develop/core/txn/command.go#L72-L98
|
||||
switch (txData.type) {
|
||||
case 'Issue Signatures':
|
||||
return TxDetailsIssueSignatures;
|
||||
case 'Submit Order':
|
||||
return TxDetailsOrder;
|
||||
case 'Submit Oracle Data':
|
||||
return TxDetailsDataSubmission;
|
||||
case 'Protocol Upgrade':
|
||||
return TxDetailsProtocolUpgrade;
|
||||
case 'Cancel Order':
|
||||
return TxDetailsOrderCancel;
|
||||
case 'Amend Order':
|
||||
|
||||
@@ -11,7 +11,8 @@ interface TxDetailsGenericProps {
|
||||
}
|
||||
|
||||
/**
|
||||
* A node is
|
||||
* If there is not yet a custom component for a transaction, just display
|
||||
* the basic details. This allows someone to view the decoded transaction.
|
||||
*/
|
||||
export const TxDetailsGeneric = ({
|
||||
txData,
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||
import { TableRow, TableCell, TableWithTbody } from '../../table';
|
||||
|
||||
import type { components } from '../../../../types/explorer';
|
||||
import {
|
||||
EthExplorerLink,
|
||||
EthExplorerLinkTypes,
|
||||
} from '../../links/eth-explorer-link/eth-explorer-link';
|
||||
import { NodeLink } from '../../links';
|
||||
|
||||
type Command = components['schemas']['v1IssueSignatures'];
|
||||
|
||||
const kind: Record<components['schemas']['v1NodeSignatureKind'], string> = {
|
||||
NODE_SIGNATURE_KIND_UNSPECIFIED: 'Unspecified',
|
||||
NODE_SIGNATURE_KIND_ASSET_NEW: 'New asset',
|
||||
NODE_SIGNATURE_KIND_ASSET_WITHDRAWAL: 'Asset withdrawal',
|
||||
NODE_SIGNATURE_KIND_ASSET_UPDATE: ' Asset update',
|
||||
NODE_SIGNATURE_KIND_ERC20_MULTISIG_SIGNER_ADDED: 'Multisig signer added',
|
||||
NODE_SIGNATURE_KIND_ERC20_MULTISIG_SIGNER_REMOVED: 'Multisig signer removed',
|
||||
};
|
||||
|
||||
interface TxDetailsGenericProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
pubKey: string | undefined;
|
||||
blockData: TendermintBlocksResponse | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is not yet a custom component for a transaction, just display
|
||||
* the basic details. This allows someone to view the decoded transaction.
|
||||
*/
|
||||
export const TxDetailsIssueSignatures = ({
|
||||
txData,
|
||||
pubKey,
|
||||
blockData,
|
||||
}: TxDetailsGenericProps) => {
|
||||
if (!txData) {
|
||||
return <>{t('Awaiting Block Explorer transaction details')}</>;
|
||||
}
|
||||
|
||||
const cmd: Command = txData.command;
|
||||
const k = cmd.kind ? kind[cmd.kind] : null;
|
||||
|
||||
return (
|
||||
<TableWithTbody className="mb-8">
|
||||
<TxDetailsShared txData={txData} pubKey={pubKey} blockData={blockData} />
|
||||
{k ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Kind')}</TableCell>
|
||||
<TableCell>{k}</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
{cmd.submitter ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('ETH key')}</TableCell>
|
||||
<TableCell>
|
||||
<EthExplorerLink
|
||||
id={cmd.submitter}
|
||||
type={EthExplorerLinkTypes.address}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
{cmd.validatorNodeId ? (
|
||||
<TableRow modifier="bordered">
|
||||
<TableCell>{t('Validator')}</TableCell>
|
||||
<TableCell>
|
||||
<NodeLink id={cmd.validatorNodeId} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : null}
|
||||
</TableWithTbody>
|
||||
);
|
||||
};
|
||||
@@ -1,11 +1,10 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
import { MarketLink } from '../../links';
|
||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||
import { TxDetailsShared } from './shared/tx-details-shared';
|
||||
import { TableCell, TableRow, TableWithTbody } from '../../table';
|
||||
|
||||
import type { components } from '../../../../types/explorer';
|
||||
import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response';
|
||||
import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response';
|
||||
|
||||
export type LiquidityCancellation =
|
||||
components['schemas']['v1LiquidityProvisionCancellation'];
|
||||
|
||||
@@ -63,7 +63,7 @@ export const TxDataView = ({ txData, blockData }: TxDataViewProps) => {
|
||||
<Select
|
||||
placeholder="View as..."
|
||||
onChange={(v) => setShowTxData(v.target.value as ShowTxDataType)}
|
||||
value={showTxData}
|
||||
value={'JSON'}
|
||||
>
|
||||
<option value={'JSON'}>JSON</option>
|
||||
<option value={'base64'}>Base64</option>
|
||||
|
||||
@@ -10,7 +10,6 @@ const truthy = ['1', 'true'];
|
||||
export const ENV = {
|
||||
// Data sources
|
||||
// Environment
|
||||
env: windowOrDefault('NX_VEGA_ENV'),
|
||||
dsn: windowOrDefault('NX_EXPLORER_SENTRY_DSN'),
|
||||
dataSources: {
|
||||
blockExplorerUrl: windowOrDefault('NX_BLOCK_EXPLORER'),
|
||||
@@ -18,7 +17,6 @@ export const ENV = {
|
||||
tendermintWebsocketUrl: windowOrDefault('NX_TENDERMINT_WEBSOCKET_URL'),
|
||||
ethExplorerUrl: windowOrDefault('NX_ETHERSCAN_URL'),
|
||||
governanceUrl: windowOrDefault('NX_VEGA_GOVERNANCE_URL'),
|
||||
vegaRepoUrl: windowOrDefault('NX_VEGA_REPO_URL'),
|
||||
},
|
||||
flags: {
|
||||
assets: truthy.includes(windowOrDefault('NX_EXPLORER_ASSETS')),
|
||||
|
||||
@@ -5,7 +5,6 @@ import type {
|
||||
BlockExplorerTransactions,
|
||||
} from '../routes/types/block-explorer-response';
|
||||
import { DATA_SOURCES } from '../config';
|
||||
import isNumber from 'lodash/isNumber';
|
||||
|
||||
export interface TxsStateProps {
|
||||
txsData: BlockExplorerTransactionResult[];
|
||||
@@ -55,15 +54,15 @@ export const useTxsData = ({ limit, filters }: IUseTxsData) => {
|
||||
} = useFetch<BlockExplorerTransactions>(url, {}, false);
|
||||
|
||||
useEffect(() => {
|
||||
if (data && isNumber(data?.transactions?.length)) {
|
||||
if (data?.transactions?.length) {
|
||||
setTxsState((prev) => ({
|
||||
txsData: [...prev.txsData, ...data.transactions],
|
||||
hasMoreTxs: data.transactions.length > 0,
|
||||
hasMoreTxs: true,
|
||||
lastCursor:
|
||||
data.transactions[data.transactions.length - 1]?.cursor || '',
|
||||
data.transactions[data.transactions.length - 1].cursor || '',
|
||||
}));
|
||||
}
|
||||
}, [setTxsState, data]);
|
||||
}, [setTxsState, data?.transactions]);
|
||||
|
||||
const loadTxs = useCallback(() => {
|
||||
return refetch({
|
||||
|
||||
@@ -10,7 +10,7 @@ export type ExplorerOracleDataConnectionFragment = { __typename?: 'OracleSpec',
|
||||
export type ExplorerOracleSpecsQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type ExplorerOracleSpecsQuery = { __typename?: 'Query', oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean }, edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } } } } } } } | null> | null } | null };
|
||||
export type ExplorerOracleSpecsQuery = { __typename?: 'Query', oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean }, edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, createdAt: any, updatedAt?: any | null, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean }, edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', matchedSpecIds?: Array<string> | null, broadcastAt: any, signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
|
||||
|
||||
export type ExplorerOracleSpecByIdQueryVariables = Types.Exact<{
|
||||
id: Types.Scalars['ID'];
|
||||
@@ -73,7 +73,7 @@ export const ExplorerOracleDataSourceFragmentDoc = gql`
|
||||
`;
|
||||
export const ExplorerOracleDataConnectionFragmentDoc = gql`
|
||||
fragment ExplorerOracleDataConnection on OracleSpec {
|
||||
dataConnection {
|
||||
dataConnection(pagination: {first: 1}) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
}
|
||||
@@ -113,11 +113,13 @@ export const ExplorerOracleSpecsDocument = gql`
|
||||
edges {
|
||||
node {
|
||||
...ExplorerOracleDataSource
|
||||
...ExplorerOracleDataConnection
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${ExplorerOracleDataSourceFragmentDoc}`;
|
||||
${ExplorerOracleDataSourceFragmentDoc}
|
||||
${ExplorerOracleDataConnectionFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useExplorerOracleSpecsQuery__
|
||||
|
||||
@@ -22,7 +22,7 @@ export type SourceType =
|
||||
interface OracleDetailsProps {
|
||||
id: string;
|
||||
dataSource: ExplorerOracleDataSourceFragment;
|
||||
dataConnection?: ExplorerOracleDataConnectionFragment;
|
||||
dataConnection: ExplorerOracleDataConnectionFragment;
|
||||
// Defaults to false. Hides the count of 'broadcasts' this oracle has seen
|
||||
showBroadcasts?: boolean;
|
||||
}
|
||||
@@ -41,8 +41,7 @@ export const OracleDetails = ({
|
||||
showBroadcasts = false,
|
||||
}: OracleDetailsProps) => {
|
||||
const sourceType = dataSource.dataSourceSpec.spec.data.sourceType;
|
||||
const reportsCount: number =
|
||||
dataConnection?.dataConnection.edges?.length || 0;
|
||||
const reportsCount: number = dataConnection.dataConnection.edges?.length || 0;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -64,9 +63,7 @@ export const OracleDetails = ({
|
||||
</TableRow>
|
||||
</TableWithTbody>
|
||||
<OracleFilter data={dataSource} />
|
||||
{showBroadcasts && dataConnection ? (
|
||||
<OracleData data={dataConnection} />
|
||||
) : null}
|
||||
{showBroadcasts ? <OracleData data={dataConnection} /> : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -28,7 +28,7 @@ const Oracles = () => {
|
||||
<OracleDetails
|
||||
id={id}
|
||||
dataSource={o?.node}
|
||||
showBroadcasts={false}
|
||||
dataConnection={o?.node}
|
||||
/>
|
||||
<details>
|
||||
<summary className="pointer">JSON</summary>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||
export const JumpToParty = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
useDocumentTitle(['Public keys']);
|
||||
useDocumentTitle(['Parties']);
|
||||
|
||||
const handleSubmit = (e: React.SyntheticEvent) => {
|
||||
e.preventDefault();
|
||||
@@ -27,8 +27,8 @@ export const JumpToParty = () => {
|
||||
};
|
||||
return (
|
||||
<JumpTo
|
||||
label={t('Go to public key')}
|
||||
placeholder={t('Public key')}
|
||||
label={t('Go to party')}
|
||||
placeholder={t('Party id')}
|
||||
inputId="party-input"
|
||||
inputType="text"
|
||||
inputName="partyId"
|
||||
@@ -40,7 +40,7 @@ export const JumpToParty = () => {
|
||||
const Parties = () => {
|
||||
return (
|
||||
<section>
|
||||
<RouteTitle data-testid="parties-header">{t('Public keys')}</RouteTitle>
|
||||
<RouteTitle data-testid="parties-header">{t('Parties')}</RouteTitle>
|
||||
<JumpToParty />
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -14,7 +14,7 @@ type PartyIdErrorProps = {
|
||||
const PartyIdError = ({ id, error }: PartyIdErrorProps) => {
|
||||
const end = isValidPartyId(id)
|
||||
? t('No accounts or transactions found for: ')
|
||||
: 'Invalid public key: ';
|
||||
: 'Invalid party id: ';
|
||||
return (
|
||||
<section>
|
||||
<p>
|
||||
|
||||
@@ -16,7 +16,7 @@ import { PartyAccounts } from './components/party-accounts';
|
||||
const Party = () => {
|
||||
const { party } = useParams<{ party: string }>();
|
||||
|
||||
useDocumentTitle(['Public keys', party || '-']);
|
||||
useDocumentTitle(['Parties', party || '-']);
|
||||
const partyId = toNonHex(party ? party : '');
|
||||
const { isMobile } = useScreenDimensions();
|
||||
const visibleChars = useMemo(() => (isMobile ? 10 : 14), [isMobile]);
|
||||
@@ -44,7 +44,7 @@ const Party = () => {
|
||||
/>
|
||||
) : (
|
||||
<Panel>
|
||||
<p>No data found for public key {party}</p>
|
||||
<p>No party found for key {party}</p>
|
||||
</Panel>
|
||||
);
|
||||
|
||||
@@ -71,7 +71,7 @@ const Party = () => {
|
||||
className="font-alpha uppercase font-xl mb-4 text-zinc-800 dark:text-zinc-200"
|
||||
data-testid="parties-header"
|
||||
>
|
||||
{t('Public key')}
|
||||
{t('Party')}
|
||||
</h1>
|
||||
{partyRes.data ? (
|
||||
<>
|
||||
|
||||
@@ -38,7 +38,7 @@ const Tx = () => {
|
||||
to={`/${Routes.TX}`}
|
||||
>
|
||||
<Icon
|
||||
className="text-vega-light-150 dark:text-vega-light-150"
|
||||
className="text-vega-light-300 dark:text-vega-light-300"
|
||||
name={IconNames.CHEVRON_LEFT}
|
||||
/>
|
||||
All Transactions
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 104 KiB |
File diff suppressed because it is too large
Load Diff
@@ -16,16 +16,4 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
#Test configuration variables
|
||||
CYPRESS_FAIRGROUND=false
|
||||
CYPRESS_VEGA_URL=http://localhost:3028/query
|
||||
CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session
|
||||
CYPRESS_ETHEREUM_PROVIDER_URL=http://localhost:8545
|
||||
CYPRESS_EXPLORER_URL=https://explorer.fairground.wtf
|
||||
CYPRESS_FAUCET_URL=http://localhost:1790/api/v1/mint
|
||||
CYPRESS_TRUNCATED_VEGA_PUBLIC_KEY=02ecea…342f65
|
||||
CYPRESS_TRUNCATED_VEGA_PUBLIC_KEY2=7f9cf0…c25535
|
||||
CYPRESS_VEGA_ENV=CUSTOM
|
||||
CYPRESS_VEGA_PUBLIC_KEY=02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65
|
||||
CYPRESS_VEGA_PUBLIC_KEY2=7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f48644bfc25535
|
||||
CYPRESS_VEGA_TOKEN_URL=https://token.fairground.wtf
|
||||
CYPRESS_VEGA_URL=http://localhost:3028/query
|
||||
CYPRESS_VEGA_WALLET_URL=http://localhost:1789
|
||||
CYPRESS_VEGA_WALLET_API_TOKEN=
|
||||
|
||||
@@ -2,59 +2,56 @@
|
||||
"changes": {
|
||||
"decimalPlaces": "5",
|
||||
"positionDecimalPlaces": "5",
|
||||
"lpPriceRange": "10",
|
||||
"instrument": {
|
||||
"name": "Token test market",
|
||||
"code": "Token.24h",
|
||||
"name": "Oranges Daily",
|
||||
"code": "ORANGES.24h",
|
||||
"future": {
|
||||
"settlementAsset": "fBTC",
|
||||
"quoteName": "fBTC",
|
||||
"settlementAsset": "8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4",
|
||||
"quoteName": "tEuro",
|
||||
"settlementDataDecimals": 5,
|
||||
"dataSourceSpecForSettlementData": {
|
||||
"external": {
|
||||
"oracle": {
|
||||
"signers": [
|
||||
{
|
||||
"pubKey": {
|
||||
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "prices.ETH.value",
|
||||
"type": "TYPE_INTEGER",
|
||||
"numberDecimalPlaces": "0"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN",
|
||||
"value": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"dataSourceSpecForTradingTermination": {
|
||||
"signers": [
|
||||
{
|
||||
"pubKey": {
|
||||
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
|
||||
"signer": {
|
||||
"__typename": "ETHAddress",
|
||||
"address": "0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "trading.terminated.ETH5",
|
||||
"type": "TYPE_BOOLEAN"
|
||||
"name": "prices.BTC.value",
|
||||
"type": "TYPE_INTEGER"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_EQUALS",
|
||||
"value": "true"
|
||||
"operator": "OPERATOR_GREATER_THAN",
|
||||
"value": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"dataSourceSpecForTradingTermination": {
|
||||
"signers": [
|
||||
{
|
||||
"signer": {
|
||||
"__typename": "ETHAddress",
|
||||
"address": "0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "vegaprotocol.builtin.timestamp",
|
||||
"type": "TYPE_TIMESTAMP"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN_OR_EQUAL",
|
||||
"value": "1648684800000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -62,7 +59,7 @@
|
||||
},
|
||||
"dataSourceSpecBinding": {
|
||||
"settlementPriceProperty": "prices.BTC.value",
|
||||
"tradingTerminationProperty": "trading.terminated.ETH5"
|
||||
"tradingTerminationProperty": "vegaprotocol.builtin.timestamp"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,78 +1,83 @@
|
||||
{
|
||||
"instrument": {
|
||||
"code": "TEST.24h",
|
||||
"future": {
|
||||
"quoteName": "fUSDC",
|
||||
"settlementDataDecimals": 5,
|
||||
"dataSourceSpecForSettlementData": {
|
||||
"signers": [
|
||||
{
|
||||
"pubKey": {
|
||||
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "prices.ETH.value",
|
||||
"type": "TYPE_INTEGER"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN",
|
||||
"value": "0"
|
||||
"marketId": "315a8e48db0a292c92b617264728048c82c20efc922c75fd292fc54e5c727c81",
|
||||
"changes": {
|
||||
"instrument": {
|
||||
"code": "ORANGES.24h",
|
||||
"future": {
|
||||
"quoteName": "tEuro",
|
||||
"settlementDataDecimals": 5,
|
||||
"dataSourceSpecForSettlementData": {
|
||||
"signers": [
|
||||
{
|
||||
"signer": {
|
||||
"__typename": "ETHAddress",
|
||||
"address": "0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"dataSourceSpecForTradingTermination": {
|
||||
"signers": [
|
||||
{
|
||||
"pubKey": {
|
||||
"key": "70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "trading.terminated.ETH5",
|
||||
"type": "TYPE_BOOLEAN"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN_OR_EQUAL",
|
||||
"value": "1648684800000000000"
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "prices.BTC.value",
|
||||
"type": "TYPE_INTEGER"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN",
|
||||
"value": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"dataSourceSpecForTradingTermination": {
|
||||
"signers": [
|
||||
{
|
||||
"signer": {
|
||||
"__typename": "ETHAddress",
|
||||
"address": "0xfCEAdAFab14d46e20144F48824d0C09B1a03F2BC"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"dataSourceSpecBinding": {
|
||||
"settlementPriceProperty": "prices.ETH.value",
|
||||
"tradingTerminationProperty": "trading.terminated.ETH5"
|
||||
}
|
||||
],
|
||||
"filters": [
|
||||
{
|
||||
"key": {
|
||||
"name": "vegaprotocol.builtin.timestamp",
|
||||
"type": "TYPE_TIMESTAMP"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"operator": "OPERATOR_GREATER_THAN_OR_EQUAL",
|
||||
"value": "1648684800000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"dataSourceSpecBinding": {
|
||||
"settlementPriceProperty": "prices.BTC.value",
|
||||
"tradingTerminationProperty": "vegaprotocol.builtin.timestamp"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"metadata": ["sector:energy", "sector:food", "source:docs.vega.xyz"],
|
||||
"priceMonitoringParameters": {
|
||||
"triggers": [
|
||||
{
|
||||
"horizon": "43200",
|
||||
"probability": "0.9999999",
|
||||
"auctionExtension": "600"
|
||||
},
|
||||
"metadata": ["sector:energy", "sector:food", "source:docs.vega.xyz"],
|
||||
"priceMonitoringParameters": {
|
||||
"triggers": [
|
||||
{
|
||||
"horizon": "43200",
|
||||
"probability": "0.9999999",
|
||||
"auctionExtension": "600"
|
||||
}
|
||||
]
|
||||
},
|
||||
"logNormal": {
|
||||
"tau": 0.0001140771161,
|
||||
"riskAversionParameter": 0.001,
|
||||
"params": {
|
||||
"mu": 0,
|
||||
"r": 0.016,
|
||||
"sigma": 0.3
|
||||
}
|
||||
]
|
||||
},
|
||||
"logNormal": {
|
||||
"tau": 0.0001140771161,
|
||||
"riskAversionParameter": 0.001,
|
||||
"params": {
|
||||
"mu": 0,
|
||||
"r": 0.016,
|
||||
"sigma": 0.3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
0123245
|
||||
123
|
||||
|
||||
@@ -11,7 +11,6 @@ const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||
const dialogCloseButton = '[data-testid="dialog-close"]';
|
||||
const viewProposalButton = '[data-testid="view-proposal-btn"]';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const closedProposals = '[data-testid="closed-proposals"]';
|
||||
const proposalVoteProgressForPercentage =
|
||||
'[data-testid="vote-progress-indicator-percentage-for"]';
|
||||
const proposalVoteProgressAgainstPercentage =
|
||||
@@ -23,9 +22,7 @@ const proposalVoteProgressAgainstTokens =
|
||||
const changeVoteButton = '[data-testid="change-vote-button"]';
|
||||
const proposalDetailsTitle = '[data-testid="proposal-title"]';
|
||||
const proposalDetailsDescription = '[data-testid="proposal-description"]';
|
||||
const proposalStatus = '[data-testid="proposal-status"]';
|
||||
const rawProposalData = '[data-testid="proposal-data"]';
|
||||
const votesTable = '[data-testid="votes-table"]';
|
||||
const minVoteButton = '[data-testid="min-vote"]';
|
||||
const maxVoteButton = '[data-testid="max-vote"]';
|
||||
const voteButtons = '[data-testid="vote-buttons"]';
|
||||
@@ -40,10 +37,6 @@ const txTimeout = Cypress.env('txTimeout');
|
||||
const epochTimeout = Cypress.env('epochTimeout');
|
||||
const proposalTimeout = { timeout: 14000 };
|
||||
|
||||
const minCloseDays = 2;
|
||||
const maxCloseDays = 3;
|
||||
const requiredParticipation = 0.001;
|
||||
|
||||
const governanceProposalType = {
|
||||
NETWORK_PARAMETER: 'Network parameter',
|
||||
NEW_MARKET: 'New market',
|
||||
@@ -72,6 +65,21 @@ context(
|
||||
network_parameters['governance.proposal.freeform.requiredMajority'] *
|
||||
100
|
||||
).as('requiredMajority');
|
||||
cy.wrap(
|
||||
network_parameters[
|
||||
'governance.proposal.freeform.requiredParticipation'
|
||||
] * 100
|
||||
).as('requiredParticipation');
|
||||
cy.wrap(
|
||||
network_parameters['governance.proposal.freeform.minClose'].split(
|
||||
'h'
|
||||
)[0] / 24
|
||||
).as('minCloseDays');
|
||||
cy.wrap(
|
||||
network_parameters['governance.proposal.freeform.maxClose'].split(
|
||||
'h'
|
||||
)[0] / 24
|
||||
).as('maxCloseDays');
|
||||
cy.wrap(
|
||||
network_parameters['governance.proposal.freeform.minClose'].split(
|
||||
'h'
|
||||
@@ -100,6 +108,21 @@ context(
|
||||
0.00001,
|
||||
'Asserting that value is at least 0.00001 for network parameter minVoterBalance'
|
||||
);
|
||||
assert.isAtLeast(
|
||||
parseFloat(this.requiredParticipation),
|
||||
0.00001,
|
||||
'Asserting that value is at least 0.00001 for network parameter requiredParticipation'
|
||||
);
|
||||
assert.isAtLeast(
|
||||
parseInt(this.minCloseDays),
|
||||
1,
|
||||
'Asserting that value is at least 1 for network parameter minCloseDays'
|
||||
);
|
||||
assert.isAtLeast(
|
||||
parseInt(this.maxCloseDays),
|
||||
parseInt(this.minCloseDays + 1),
|
||||
'Asserting that network parameter maxCloseDays is at least 1 day higher than minCloseDays'
|
||||
);
|
||||
// workaround for first eth tx hanging
|
||||
associateTokenStartOfTests();
|
||||
}
|
||||
@@ -159,10 +182,10 @@ context(
|
||||
this.minProposerBalance
|
||||
);
|
||||
let proposalDays = [
|
||||
minCloseDays + 1,
|
||||
maxCloseDays,
|
||||
minCloseDays + 3,
|
||||
minCloseDays + 2,
|
||||
this.minCloseDays + 1,
|
||||
this.maxCloseDays,
|
||||
this.minCloseDays + 3,
|
||||
this.minCloseDays + 2,
|
||||
];
|
||||
for (var index = 0; index < proposalDays.length; index++) {
|
||||
cy.go_to_make_new_proposal(governanceProposalType.RAW);
|
||||
@@ -204,7 +227,6 @@ context(
|
||||
cy.navigate_to('validators');
|
||||
cy.click_on_validator_from_list(0);
|
||||
cy.staking_validator_page_add_stake('2');
|
||||
cy.close_staking_dialog();
|
||||
|
||||
cy.get(vegaWalletStakedBalances, txTimeout).should('contain', '2');
|
||||
|
||||
@@ -275,12 +297,10 @@ context(
|
||||
});
|
||||
});
|
||||
|
||||
// 3001-VOTE-071
|
||||
it('Newly created freeform proposals list - shows proposal participation - both met and not', function () {
|
||||
const proposalTitle = generateProposalTitle();
|
||||
createFreeformProposal(this.minProposerBalance, proposalTitle);
|
||||
|
||||
cy.get_submitted_proposal_from_proposal_list(proposalTitle)
|
||||
// Skipping test due to bug: #1320
|
||||
it.skip('Newly created freeform proposals list - shows proposal participation - both met and not', function () {
|
||||
createFreeformProposal(this.minProposerBalance);
|
||||
cy.get_submitted_proposal_from_proposal_list()
|
||||
.as('submittedProposal')
|
||||
.within(() => {
|
||||
// 3001-VOTE-039
|
||||
@@ -292,7 +312,7 @@ context(
|
||||
.invoke('text')
|
||||
.then((totalSupply) => {
|
||||
let tokensRequiredToAchieveResult = parseFloat(
|
||||
(totalSupply.replace(/,/g, '') * requiredParticipation) / 100
|
||||
(totalSupply.replace(/,/g, '') * this.requiredParticipation) / 100
|
||||
).toFixed(2);
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
tokensRequiredToAchieveResult
|
||||
@@ -301,17 +321,16 @@ context(
|
||||
cy.get('@submittedProposal').within(() =>
|
||||
cy.get(viewProposalButton).click()
|
||||
);
|
||||
cy.get_proposal_information_from_table('Token participation met')
|
||||
cy.get_proposal_information_from_table('Participation met')
|
||||
.contains('👍')
|
||||
.should('be.visible');
|
||||
cy.navigate_to('proposals');
|
||||
cy.get('@submittedProposal').within(() =>
|
||||
cy.get(voteStatus).should('have.text', 'Set to pass')
|
||||
cy.get(voteStatus).should('have.text', 'Participation met')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// 3001-VOTE-055
|
||||
it('Newly created raw proposal details - shows proposal title and full description', function () {
|
||||
createRawProposal(this.minProposerBalance);
|
||||
cy.get('@rawProposal').then((rawProposal) => {
|
||||
@@ -338,7 +357,6 @@ context(
|
||||
});
|
||||
});
|
||||
|
||||
// 3001-VOTE-043
|
||||
it('Newly created freeform proposal details - shows proposed and closing dates', function () {
|
||||
const closingVoteHrs = '72';
|
||||
const proposalTitle = generateProposalTitle();
|
||||
@@ -381,7 +399,6 @@ context(
|
||||
it('Newly created proposal details - shows default status set to fail', function () {
|
||||
// 3001-VOTE-037
|
||||
// 3001-VOTE-040
|
||||
// 3001-VOTE-067
|
||||
createRawProposal(this.minProposerBalance);
|
||||
cy.get('@rawProposal').then((rawProposal) => {
|
||||
cy.get_submitted_proposal_from_proposal_list(
|
||||
@@ -396,17 +413,15 @@ context(
|
||||
.should('be.visible');
|
||||
// 3001-VOTE-062
|
||||
// 3001-VOTE-040
|
||||
// 3001-VOTE-070
|
||||
cy.get_proposal_information_from_table('Token majority met')
|
||||
.contains('👎')
|
||||
.should('be.visible');
|
||||
// 3001-VOTE-068
|
||||
cy.get_proposal_information_from_table('Token participation met')
|
||||
.contains('👎')
|
||||
.should('be.visible');
|
||||
});
|
||||
|
||||
// 3001-VOTE-080 3001-VOTE-090 3001-VOTE-069 3001-VOTE-072 3001-VOTE-073
|
||||
// 3001-VOTE-080 3001-VOTE-090
|
||||
it('Newly created proposal details - ability to vote for and against proposal - with minimum required tokens associated', function () {
|
||||
createRawProposal(this.minProposerBalance);
|
||||
cy.get('@rawProposal').then((rawProposal) => {
|
||||
@@ -431,7 +446,7 @@ context(
|
||||
.contains(votedDate)
|
||||
.should('be.visible');
|
||||
});
|
||||
cy.get(proposalVoteProgressForPercentage) // 3001-VOTE-072
|
||||
cy.get(proposalVoteProgressForPercentage)
|
||||
.contains('100.00%')
|
||||
.and('be.visible');
|
||||
cy.get(proposalVoteProgressAgainstPercentage)
|
||||
@@ -451,10 +466,10 @@ context(
|
||||
.and('be.visible');
|
||||
// 3001-VOTE-061
|
||||
cy.get_proposal_information_from_table('Participation required')
|
||||
.contains(`${requiredParticipation}%`)
|
||||
.contains(`${this.requiredParticipation}%`)
|
||||
.should('be.visible');
|
||||
// 3001-VOTE-066
|
||||
cy.get_proposal_information_from_table('Majority Required') // 3001-VOTE-073
|
||||
cy.get_proposal_information_from_table('Majority Required')
|
||||
.contains(`${parseFloat(this.requiredMajority).toFixed(2)}%`)
|
||||
.should('be.visible');
|
||||
cy.get_proposal_information_from_table('Number of voting parties')
|
||||
@@ -497,7 +512,7 @@ context(
|
||||
.invoke('text')
|
||||
.then((totalSupply) => {
|
||||
let tokensRequiredToAchieveResult = parseFloat(
|
||||
(totalSupply.replace(/,/g, '') * requiredParticipation) / 100
|
||||
(totalSupply.replace(/,/g, '') * this.requiredParticipation) / 100
|
||||
).toFixed(2);
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
tokensRequiredToAchieveResult
|
||||
@@ -521,11 +536,6 @@ context(
|
||||
cy.get(proposalVoteProgressAgainstTokens)
|
||||
.contains('0.00')
|
||||
.and('be.visible');
|
||||
cy.get_proposal_information_from_table(
|
||||
'Total tokens voted percentage'
|
||||
)
|
||||
.should('have.text', '0.00%')
|
||||
.and('be.visible');
|
||||
cy.get_proposal_information_from_table('Tokens for proposal')
|
||||
.should('have.text', tokensRequiredToAchieveResult)
|
||||
.and('be.visible');
|
||||
@@ -578,7 +588,6 @@ context(
|
||||
);
|
||||
});
|
||||
|
||||
// 3001-VOTE-006
|
||||
it('Creating a proposal - proposal rejected - able to access rejected proposals', function () {
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
this.minProposerBalance
|
||||
@@ -640,7 +649,6 @@ context(
|
||||
cy.get(dialogCloseButton).click();
|
||||
});
|
||||
|
||||
// 3002-PROP-009
|
||||
it('Unable to create a proposal - when some but not enough tokens are associated', function () {
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
this.minProposerBalance - 0.000001
|
||||
@@ -661,7 +669,7 @@ context(
|
||||
});
|
||||
|
||||
it('Unable to create a freeform proposal - when json parent section contains unexpected field', function () {
|
||||
// 3001-VOTE-038 3002-PROP-013 3002-PROP-014
|
||||
// 3001-VOTE-038
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
this.minProposerBalance
|
||||
);
|
||||
@@ -687,9 +695,6 @@ context(
|
||||
'Invalid params: the transaction is malformed'
|
||||
);
|
||||
cy.get(dialogCloseButton).click();
|
||||
cy.get(rawProposalData)
|
||||
.invoke('val')
|
||||
.should('contain', "i shouldn't be here");
|
||||
});
|
||||
|
||||
it('Unable to create a freeform proposal - when json terms section contains unexpected field', function () {
|
||||
@@ -787,107 +792,6 @@ context(
|
||||
cy.contains('You voted: Against').should('be.visible');
|
||||
});
|
||||
|
||||
// 3001-VOTE-006
|
||||
it('Able to view enacted proposal', function () {
|
||||
cy.createMarket();
|
||||
cy.reload();
|
||||
cy.wait_for_spinner();
|
||||
cy.get(closedProposals).within(() => {
|
||||
cy.get(proposalDetailsTitle).should(
|
||||
'have.text',
|
||||
'Add Lorem Ipsum market'
|
||||
);
|
||||
cy.get(proposalStatus).should('have.text', 'Enacted ');
|
||||
cy.get(viewProposalButton).click();
|
||||
});
|
||||
cy.getByTestId('proposal-type').should('have.text', 'New market');
|
||||
cy.get_proposal_information_from_table('State')
|
||||
.contains('Enacted')
|
||||
.and('be.visible');
|
||||
cy.get(votesTable).within(() => {
|
||||
cy.contains('Vote passed.').should('be.visible');
|
||||
cy.contains('Voting has ended.').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
// 3001-VOTE-047
|
||||
it('Able to enact freeform proposal', function () {
|
||||
const proposalTitle = 'Add New free form proposal with short enactment';
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
this.minProposerBalance
|
||||
);
|
||||
cy.sendWalletTxFreeFormProposal();
|
||||
cy.navigate_to('proposals');
|
||||
cy.reload();
|
||||
cy.wait_for_spinner();
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil('[data-testid="proposals-list-item"]')
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
cy.get_proposal_information_from_table('State')
|
||||
.contains('Open')
|
||||
.and('be.visible');
|
||||
cy.vote_for_proposal('for');
|
||||
cy.get_proposal_information_from_table('State')
|
||||
.contains('Enacted', epochTimeout)
|
||||
.and('be.visible');
|
||||
});
|
||||
|
||||
// 3001-VOTE-046 3001-VOTE-044 3001-VOTE-074 3001-VOTE-074
|
||||
it('Able to enact proposal by voting', function () {
|
||||
const proposalTitle = 'Add New proposal with short enactment';
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
this.minProposerBalance
|
||||
);
|
||||
cy.sendWalletTxUpdateNetworkProposal();
|
||||
cy.navigate_to('proposals');
|
||||
cy.reload();
|
||||
cy.wait_for_spinner();
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil('[data-testid="proposals-list-item"]')
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
cy.get_proposal_information_from_table('State')
|
||||
.contains('Open')
|
||||
.and('be.visible');
|
||||
cy.vote_for_proposal('for');
|
||||
cy.get_proposal_information_from_table('State') // 3001-VOTE-047
|
||||
.contains('Passed', txTimeout)
|
||||
.and('be.visible');
|
||||
cy.get_proposal_information_from_table('State')
|
||||
.contains('Enacted', epochTimeout)
|
||||
.and('be.visible');
|
||||
cy.get(votesTable).within(() => {
|
||||
cy.contains('Vote passed.').should('be.visible');
|
||||
cy.contains('Voting has ended.').should('be.visible');
|
||||
});
|
||||
cy.get(proposalVoteProgressForPercentage)
|
||||
.contains('100.00%')
|
||||
.and('be.visible');
|
||||
});
|
||||
|
||||
// 3001-VOTE-048 3001-VOTE-049
|
||||
it('Able to fail proposal due to lack of participation', function () {
|
||||
const proposalTitle = 'Add New free form proposal with short enactment';
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(
|
||||
this.minProposerBalance
|
||||
);
|
||||
cy.sendWalletTxFreeFormProposal();
|
||||
cy.navigate_to('proposals');
|
||||
cy.reload();
|
||||
cy.wait_for_spinner();
|
||||
cy.contains(proposalTitle)
|
||||
.parentsUntil('[data-testid="proposals-list-item"]')
|
||||
.within(() => cy.get(viewProposalButton).click());
|
||||
cy.get_proposal_information_from_table('State')
|
||||
.contains('Open')
|
||||
.and('be.visible');
|
||||
cy.get_proposal_information_from_table('State') // 3001-VOTE-047
|
||||
.contains('Declined', txTimeout)
|
||||
.and('be.visible');
|
||||
cy.get_proposal_information_from_table('Rejection reason')
|
||||
.contains('PROPOSAL_ERROR_PARTICIPATION_THRESHOLD_NOT_REACHED')
|
||||
.and('be.visible');
|
||||
});
|
||||
|
||||
function createRawProposal(proposerBalance) {
|
||||
if (proposerBalance)
|
||||
cy.ensure_specified_unstaked_tokens_are_associated(proposerBalance);
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
const proposalListItem = '[data-testid="proposals-list-item"]';
|
||||
const openProposals = '[data-testid="open-proposals"]';
|
||||
const proposalType = '[data-testid="proposal-type"]';
|
||||
const proposalDetails = '[data-testid="proposal-details"]';
|
||||
const newProposalSubmitButton = '[data-testid="proposal-submit"]';
|
||||
const proposalVoteDeadline = '[data-testid="proposal-vote-deadline"]';
|
||||
const proposalValidationDeadline =
|
||||
@@ -213,15 +209,18 @@ context(
|
||||
);
|
||||
});
|
||||
|
||||
// skipped because no markets available to select in capsule
|
||||
it.skip('Able to submit update market proposal', function () {
|
||||
const marketId =
|
||||
'315a8e48db0a292c92b617264728048c82c20efc922c75fd292fc54e5c727c81';
|
||||
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_MARKET);
|
||||
cy.get(newProposalTitle).type('Test update market proposal');
|
||||
cy.get(newProposalTitle).type('Test update asset proposal');
|
||||
cy.get(newProposalDescription).type('E2E test for proposals');
|
||||
cy.get(proposalMarketSelect).select('Test market 1');
|
||||
cy.get(proposalMarketSelect).select(marketId);
|
||||
cy.get('[data-testid="update-market-details"]').within(() => {
|
||||
cy.get('dd').eq(0).should('have.text', 'Test market 1');
|
||||
cy.get('dd').eq(1).should('have.text', 'TEST.24h');
|
||||
cy.get('dd').eq(2).should('not.be.empty');
|
||||
cy.get('dd').eq(0).should('have.text', 'Oranges Daily');
|
||||
cy.get('dd').eq(1).should('have.text', 'ORANGES.24h');
|
||||
cy.get('dd').eq(2).should('have.text', marketId);
|
||||
});
|
||||
cy.fixture('/proposals/update-market').then((updateMarketProposal) => {
|
||||
let newUpdateMarketProposal = JSON.stringify(updateMarketProposal);
|
||||
@@ -282,28 +281,12 @@ context(
|
||||
});
|
||||
|
||||
it('Able to submit update asset proposal using min deadline', function () {
|
||||
const assetId =
|
||||
'ebcd94151ae1f0d39a4bde3b21a9c7ae81a80ea4352fb075a92e07608d9c953d';
|
||||
|
||||
cy.go_to_make_new_proposal(governanceProposalType.UPDATE_ASSET);
|
||||
enterUpdateAssetProposalDetails();
|
||||
cy.get(minVoteDeadline).click();
|
||||
cy.get(minEnactDeadline).click();
|
||||
cy.get(newProposalSubmitButton).should('be.visible').click();
|
||||
cy.wait_for_proposal_submitted();
|
||||
cy.navigate_to('proposals');
|
||||
cy.get(openProposals).within(() => {
|
||||
cy.get(proposalType)
|
||||
.contains('Update asset')
|
||||
.parentsUntil(proposalListItem)
|
||||
.within(() => {
|
||||
cy.get(proposalDetails).should('contain.text', assetId); // 3001-VOTE-029
|
||||
cy.getByTestId('view-proposal-btn').click();
|
||||
});
|
||||
});
|
||||
cy.get_proposal_information_from_table('Proposed enactment') // 3001-VOTE-044
|
||||
.invoke('text')
|
||||
.should('not.be.empty');
|
||||
});
|
||||
|
||||
it('Able to submit update asset proposal using max deadline', function () {
|
||||
|
||||
@@ -37,8 +37,8 @@ context(
|
||||
function () {
|
||||
cy.reload();
|
||||
cy.wait_for_spinner();
|
||||
cy.ethereum_wallet_connect();
|
||||
cy.connectVegaWallet();
|
||||
cy.ethereum_wallet_connect();
|
||||
cy.vega_wallet_teardown();
|
||||
cy.navigate_to('validators');
|
||||
}
|
||||
@@ -57,16 +57,7 @@ context(
|
||||
//0005-ETXN-006
|
||||
//0005-ETXN-003
|
||||
//0005-ETXN-005
|
||||
cy.staking_page_associate_tokens('2', { skipConfirmation: true });
|
||||
|
||||
cy.getByTestId('currency-title', txTimeout).should(
|
||||
'have.length.above',
|
||||
3
|
||||
);
|
||||
cy.validate_wallet_currency('Associated', '0.00');
|
||||
cy.validate_wallet_currency('Pending association', '2.00');
|
||||
cy.validate_wallet_currency('Total associated after pending', '2.00');
|
||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
||||
cy.staking_page_associate_tokens('2');
|
||||
|
||||
// 0005-ETXN-002
|
||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
||||
@@ -107,15 +98,6 @@ context(
|
||||
|
||||
cy.staking_page_disassociate_tokens('2');
|
||||
|
||||
cy.getByTestId('currency-title', txTimeout).should(
|
||||
'have.length.above',
|
||||
3
|
||||
);
|
||||
cy.validate_wallet_currency('Associated', '2.00');
|
||||
cy.validate_wallet_currency('Pending association', '2.00');
|
||||
cy.validate_wallet_currency('Total associated after pending', '0.00');
|
||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
||||
|
||||
cy.get(ethWalletAssociatedBalances, txTimeout).should('not.exist');
|
||||
|
||||
cy.get(ethWalletTotalAssociatedBalance, txTimeout)
|
||||
@@ -212,19 +194,7 @@ context(
|
||||
// 1004-ASSO-024
|
||||
// 1004-ASSO-023
|
||||
|
||||
cy.staking_page_associate_tokens('2', {
|
||||
type: 'contract',
|
||||
skipConfirmation: true,
|
||||
});
|
||||
|
||||
cy.getByTestId('currency-title', txTimeout).should(
|
||||
'have.length.above',
|
||||
3
|
||||
);
|
||||
cy.validate_wallet_currency('Associated', '0.00');
|
||||
cy.validate_wallet_currency('Pending association', '2.00');
|
||||
cy.validate_wallet_currency('Total associated after pending', '2.00');
|
||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
||||
cy.staking_page_associate_tokens('2', { type: 'contract' });
|
||||
|
||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
||||
.contains(vegaWalletPublicKeyShort)
|
||||
@@ -240,19 +210,7 @@ context(
|
||||
});
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
|
||||
cy.staking_page_disassociate_tokens('1', {
|
||||
type: 'contract',
|
||||
skipConfirmation: true,
|
||||
});
|
||||
|
||||
cy.getByTestId('currency-title', txTimeout).should(
|
||||
'have.length.above',
|
||||
3
|
||||
);
|
||||
cy.validate_wallet_currency('Associated', '2.00');
|
||||
cy.validate_wallet_currency('Pending association', '1.00');
|
||||
cy.validate_wallet_currency('Total associated after pending', '1.00');
|
||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
||||
cy.staking_page_disassociate_tokens('1', { type: 'contract' });
|
||||
|
||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
||||
.contains(vegaWalletPublicKeyShort)
|
||||
@@ -328,35 +286,6 @@ context(
|
||||
});
|
||||
|
||||
// 1004-ASSO-004
|
||||
|
||||
it('Pending association outside of app is shown', function () {
|
||||
cy.vega_wallet_associate('2');
|
||||
cy.getByTestId('currency-title', txTimeout).should(
|
||||
'have.length.above',
|
||||
3
|
||||
);
|
||||
cy.validate_wallet_currency('Associated', '0.00');
|
||||
cy.validate_wallet_currency('Pending association', '2.00');
|
||||
cy.validate_wallet_currency('Total associated after pending', '2.00');
|
||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
||||
cy.validate_wallet_currency('Associated', '2.00');
|
||||
});
|
||||
|
||||
it('Disassociation outside of app is shown', function () {
|
||||
cy.staking_page_associate_tokens('2');
|
||||
cy.validate_wallet_currency('Associated', '2.00');
|
||||
cy.vega_wallet_disassociate('2');
|
||||
cy.getByTestId('currency-title', txTimeout).should(
|
||||
'have.length.above',
|
||||
3
|
||||
);
|
||||
cy.validate_wallet_currency('Associated', '2.00');
|
||||
cy.validate_wallet_currency('Pending association', '2.00');
|
||||
cy.validate_wallet_currency('Total associated after pending', '0.00');
|
||||
cy.getByTestId('currency-title', txTimeout).should('have.length', 3);
|
||||
cy.validate_wallet_currency('Associated', '0.00');
|
||||
});
|
||||
|
||||
it('Able to associate tokens to different public key of connected vega wallet', function () {
|
||||
cy.get(ethWalletAssociateButton).first().click();
|
||||
cy.get(associateWalletRadioButton).click();
|
||||
@@ -381,7 +310,6 @@ context(
|
||||
'vegaWalletPublicKey2Short'
|
||||
)} can now participate in governance and nominate a validator with your associated $VEGA.`
|
||||
);
|
||||
cy.staking_page_disassociate_all_tokens();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,10 +20,7 @@ context('View functionality with public key', { tags: '@smoke' }, function () {
|
||||
|
||||
it('Able to connect public key via wallet', function () {
|
||||
verifyConnectedToPubKey();
|
||||
cy.getByTestId('currency-title', Cypress.env('epochTimeout')).should(
|
||||
'contain.text',
|
||||
'USDC (fake)'
|
||||
);
|
||||
cy.getByTestId('currency-title').should('contain.text', 'USDC (fake)');
|
||||
});
|
||||
|
||||
it('Able to connect public key using url', function () {
|
||||
|
||||
@@ -321,8 +321,6 @@ context(
|
||||
'200000',
|
||||
vegaWalletPublicKey
|
||||
);
|
||||
cy.reload();
|
||||
cy.wait_for_spinner();
|
||||
cy.connectVegaWallet();
|
||||
cy.ethereum_wallet_connect();
|
||||
});
|
||||
|
||||
@@ -46,6 +46,6 @@ Cypress.Commands.add('verify_page_header', (text) => {
|
||||
});
|
||||
|
||||
Cypress.Commands.add('wait_for_spinner', () => {
|
||||
cy.get(navigation.pageSpinner, Cypress.env('epochTimeout')).should('exist');
|
||||
cy.get(navigation.pageSpinner).should('exist');
|
||||
cy.get(navigation.pageSpinner, { timeout: 20000 }).should('not.exist');
|
||||
});
|
||||
|
||||
@@ -6,7 +6,6 @@ import './governance.functions.js';
|
||||
import './wallet-eth.functions.js';
|
||||
import './wallet-teardown.functions.js';
|
||||
import './wallet-vega.functions.js';
|
||||
import './proposal.functions.js';
|
||||
import registerCypressGrep from '@cypress/grep';
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { chainIdQuery, statisticsQuery } from '@vegaprotocol/mock';
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
import { addSeconds, millisecondsToSeconds } from 'date-fns';
|
||||
|
||||
const walletName = Cypress.env('vegaWalletName');
|
||||
const walletPubKey = Cypress.env('vegaWalletPublicKey');
|
||||
const walletLocation = Cypress.env('vegaWalletLocation');
|
||||
const walletPassphraseFile = './src/fixtures/wallet/passphrase';
|
||||
|
||||
Cypress.Commands.add('sendWalletTxUpdateNetworkProposal', () => {
|
||||
const MIN_CLOSE_SEC = 8;
|
||||
const MIN_ENACT_SEC = 5;
|
||||
|
||||
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
||||
const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC);
|
||||
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
||||
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
|
||||
|
||||
cy.exec(
|
||||
`vegawallet transaction send --wallet ${walletName} --pubkey ${walletPubKey} -p ${walletPassphraseFile} --network DV '{
|
||||
"proposalSubmission": {
|
||||
"rationale": {
|
||||
"title": "Add New proposal with short enactment",
|
||||
"description": "E2E enactment test"
|
||||
},
|
||||
"terms": {
|
||||
"updateNetworkParameter": {
|
||||
"changes": {
|
||||
"key": "governance.proposal.updateNetParam.minProposerBalance",
|
||||
"value": "2"
|
||||
}
|
||||
},
|
||||
"closingTimestamp": ${closingTimestamp},
|
||||
"enactmentTimestamp": ${enactmentTimestamp}
|
||||
}
|
||||
}
|
||||
}' --home ${walletLocation}`,
|
||||
{ failOnNonZeroExit: false }
|
||||
)
|
||||
.its('stderr')
|
||||
.should('contain', '');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('sendWalletTxUpdateAssetProposal', () => {
|
||||
const MIN_CLOSE_SEC = 8;
|
||||
const MIN_ENACT_SEC = 5;
|
||||
|
||||
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
||||
const enactmentDate = addSeconds(closingDate, MIN_ENACT_SEC);
|
||||
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
||||
const enactmentTimestamp = millisecondsToSeconds(enactmentDate.getTime());
|
||||
|
||||
cy.exec(
|
||||
`vegawallet transaction send --wallet ${walletName} --pubkey ${walletPubKey} -p ${walletPassphraseFile} --network DV '{
|
||||
"proposalSubmission": {
|
||||
"rationale": {
|
||||
"title": "Update Asset set to fail",
|
||||
"description": "E2E fail test"
|
||||
},
|
||||
"terms": {
|
||||
"updateAsset": {
|
||||
"assetId": "ebcd94151ae1f0d39a4bde3b21a9c7ae81a80ea4352fb075a92e07608d9c953d",
|
||||
"changes": {
|
||||
"quantum": "1",
|
||||
"erc20": {
|
||||
"withdrawThreshold": "10",
|
||||
"lifetimeLimit": "10"
|
||||
}
|
||||
}
|
||||
},
|
||||
"closingTimestamp": ${closingTimestamp},
|
||||
"enactmentTimestamp": ${enactmentTimestamp}
|
||||
}
|
||||
}
|
||||
}' --home ${walletLocation}`,
|
||||
{ failOnNonZeroExit: false }
|
||||
)
|
||||
.its('stderr')
|
||||
.should('contain', '');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('sendWalletTxFreeFormProposal', () => {
|
||||
const MIN_CLOSE_SEC = 5;
|
||||
|
||||
const closingDate = addSeconds(new Date(), MIN_CLOSE_SEC);
|
||||
const closingTimestamp = millisecondsToSeconds(closingDate.getTime());
|
||||
|
||||
cy.exec(
|
||||
`vegawallet transaction send --wallet ${walletName} --pubkey ${walletPubKey} -p ${walletPassphraseFile} --network DV '{
|
||||
"proposalSubmission": {
|
||||
"rationale": {
|
||||
"title": "Add New free form proposal with short enactment",
|
||||
"description": "E2E enactment test"
|
||||
},
|
||||
"terms": {
|
||||
"newFreeform": {},
|
||||
"closingTimestamp": ${closingTimestamp}
|
||||
}
|
||||
}
|
||||
}' --home ${walletLocation}`,
|
||||
{ failOnNonZeroExit: false }
|
||||
)
|
||||
.its('stderr')
|
||||
.should('contain', '');
|
||||
});
|
||||
@@ -58,8 +58,6 @@ Cypress.Commands.add('staking_validator_page_remove_stake', (stake) => {
|
||||
Cypress.Commands.add('staking_page_associate_tokens', (amount, options) => {
|
||||
let approve = options && options.approve ? options.approve : false;
|
||||
let type = options && options.type ? options.type : 'wallet';
|
||||
let skipConfirmation =
|
||||
options && options.skipConfirmation ? options.skipConfirmation : false;
|
||||
|
||||
cy.highlight(`Associating ${amount} tokens from ${type}`);
|
||||
cy.get(ethWalletAssociateButton).first().click();
|
||||
@@ -81,19 +79,16 @@ Cypress.Commands.add('staking_page_associate_tokens', (amount, options) => {
|
||||
);
|
||||
}
|
||||
cy.get(tokenSubmitButton, txTimeout).should('be.enabled').click();
|
||||
|
||||
if (!skipConfirmation) {
|
||||
cy.contains(
|
||||
`Associating with Vega key. Waiting for ${Cypress.env(
|
||||
'blockConfirmations'
|
||||
)} more confirmations..`,
|
||||
txTimeout
|
||||
).should('be.visible');
|
||||
cy.contains(
|
||||
'can now participate in governance and nominate a validator',
|
||||
txTimeout
|
||||
).should('be.visible');
|
||||
}
|
||||
cy.contains(
|
||||
`Associating with Vega key. Waiting for ${Cypress.env(
|
||||
'blockConfirmations'
|
||||
)} more confirmations..`,
|
||||
txTimeout
|
||||
).should('be.visible');
|
||||
cy.contains(
|
||||
'can now participate in governance and nominate a validator',
|
||||
txTimeout
|
||||
).should('be.visible');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('staking_page_disassociate_tokens', (amount, options) => {
|
||||
@@ -221,19 +216,3 @@ Cypress.Commands.add('close_staking_dialog', () => {
|
||||
cy.get('a').should('have.text', 'Back to Staking').click();
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
'validate_wallet_currency',
|
||||
(currencyTitle, expectedAmount) => {
|
||||
cy.get("[data-testid='currency-title']")
|
||||
.contains(currencyTitle)
|
||||
.parent()
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.getByTestId('currency-value', txTimeout).should(
|
||||
'have.text',
|
||||
expectedAmount
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import { ethers, Wallet } from 'ethers';
|
||||
|
||||
const vegaWalletContainer = '[data-testid="vega-wallet"]';
|
||||
const vegaWalletAssociatedBalance = '[data-testid="currency-value"]';
|
||||
const vegaWalletMnemonic = Cypress.env('vegaWalletMnemonic');
|
||||
const vegaWalletPubKey = Cypress.env('vegaWalletPublicKey');
|
||||
const vegaTokenContractAddress = Cypress.env('vegaTokenContractAddress');
|
||||
@@ -42,11 +43,6 @@ before('Vega wallet teardown prep', function () {
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
cy.wrap(this.stakingBridgeContract).as('stakingBridgeContract');
|
||||
cy.wrap(this.vestingContract).as('vestingContract');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('deposit_asset', function (assetEthAddress) {
|
||||
cy.get('@signer', { log: false }).then((signer) => {
|
||||
// Approve asset
|
||||
@@ -95,18 +91,29 @@ Cypress.Commands.add('faucet_asset', function (assetEthAddress) {
|
||||
});
|
||||
|
||||
Cypress.Commands.add('vega_wallet_teardown', function () {
|
||||
cy.get('body').then(($body) => {
|
||||
if ($body.find('[data-testid="eth-wallet-associated-balances"]').length) {
|
||||
cy.vega_wallet_teardown_vesting(this.vestingContract);
|
||||
cy.vega_wallet_teardown_staking(this.stakingBridgeContract);
|
||||
}
|
||||
});
|
||||
cy.get(vegaWalletContainer).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance)
|
||||
.first()
|
||||
.invoke('text')
|
||||
.then((balance) => {
|
||||
if (balance != '0.00') {
|
||||
cy.vega_wallet_teardown_vesting(this.vestingContract);
|
||||
cy.vega_wallet_teardown_staking(this.stakingBridgeContract);
|
||||
}
|
||||
});
|
||||
cy.get('[data-testid="associated-amount"]', { timeout: 30000 }).should(
|
||||
'contain.text',
|
||||
'0.00'
|
||||
);
|
||||
});
|
||||
|
||||
cy.get(vegaWalletContainer).within(() => {
|
||||
cy.get(vegaWalletAssociatedBalance, { timeout: transactionTimeout }).should(
|
||||
'contain',
|
||||
'0.00',
|
||||
{ timeout: transactionTimeout }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
@@ -169,22 +176,6 @@ Cypress.Commands.add('vega_wallet_teardown_vesting', (vestingContract) => {
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('vega_wallet_associate', (amount) => {
|
||||
amount = amount + '0'.repeat(18);
|
||||
cy.highlight('Associating tokens');
|
||||
cy.get('@stakingBridgeContract').then((stakingBridgeContract) => {
|
||||
stakingBridgeContract.stake(amount, vegaWalletPubKey);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('vega_wallet_disassociate', (amount) => {
|
||||
amount = amount + '0'.repeat(18);
|
||||
cy.highlight('Disassociating tokens');
|
||||
cy.get('@stakingBridgeContract').then((stakingBridgeContract) => {
|
||||
stakingBridgeContract.remove_stake(amount, vegaWalletPubKey);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('wait_for_transaction', (tx) => {
|
||||
cy.wrap(tx.wait(1).catch(cy.log), { timeout: transactionTimeout });
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_ENV=TESTNET
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json
|
||||
NX_VEGA_URL=https://api.n08.testnet.vega.xyz/graphql
|
||||
NX_VEGA_URL=https://api.n10.testnet.vega.xyz/graphql
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
|
||||
@@ -12,10 +12,5 @@ export default {
|
||||
moduleNameMapper: {
|
||||
'^d3-(.*)$': `d3-$1/dist/d3-$1`,
|
||||
},
|
||||
collectCoverageFrom: [
|
||||
'**/*.{ts,tsx}',
|
||||
'!**/node_modules/**',
|
||||
'!**/__generated__/**',
|
||||
'!**/__generated___/**',
|
||||
],
|
||||
collectCoverageFrom: ['**/*.{ts,tsx}', '!**/node_modules/**'],
|
||||
};
|
||||
|
||||
@@ -8,7 +8,6 @@ import { AppLoader } from './app-loader';
|
||||
import { NetworkInfo } from '@vegaprotocol/network-info';
|
||||
import { BalanceManager } from './components/balance-manager';
|
||||
import { EthWallet } from './components/eth-wallet';
|
||||
import { AppLayout } from './components/page-templates/app-layout';
|
||||
import { TemplateSidebar } from './components/page-templates/template-sidebar';
|
||||
import { TransactionModal } from './components/transactions-modal';
|
||||
import { VegaWallet } from './components/vega-wallet';
|
||||
@@ -89,14 +88,14 @@ const Web3Container = ({
|
||||
<AppLoader>
|
||||
<BalanceManager>
|
||||
<>
|
||||
<AppLayout>
|
||||
<div className="app w-full max-w-[1500px] mx-auto grid grid-rows-[min-content_min-content_1fr_min-content] min-h-full border-neutral-700 lg:border-l lg:border-r lg:text-body-large">
|
||||
<TemplateSidebar sidebar={sideBar}>
|
||||
<AppRouter />
|
||||
</TemplateSidebar>
|
||||
<footer className="p-4 border-t border-neutral-700">
|
||||
<NetworkInfo />
|
||||
</footer>
|
||||
</AppLayout>
|
||||
</div>
|
||||
<VegaWalletDialogs />
|
||||
<TransactionModal />
|
||||
<WithdrawalDialog />
|
||||
|
||||
@@ -2,24 +2,20 @@ import * as Sentry from '@sentry/react';
|
||||
import { toBigNum } from '@vegaprotocol/react-helpers';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { useAppState } from '../../contexts/app-state/app-state-context';
|
||||
import { useContracts } from '../../contexts/contracts/contracts-context';
|
||||
import { useGetAssociationBreakdown } from '../../hooks/use-get-association-breakdown';
|
||||
import { useGetUserTrancheBalances } from '../../hooks/use-get-user-tranche-balances';
|
||||
import { useBalances } from '../../lib/balances/balances-store';
|
||||
import type { ReactElement } from 'react';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useListenForStakingEvents as useListenForAssociationEvents } from '../../hooks/use-listen-for-staking-events';
|
||||
|
||||
interface BalanceManagerProps {
|
||||
children: ReactElement;
|
||||
children: React.ReactElement;
|
||||
}
|
||||
|
||||
export const BalanceManager = ({ children }: BalanceManagerProps) => {
|
||||
const contracts = useContracts();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { account } = useWeb3React();
|
||||
const {
|
||||
appState: { decimals },
|
||||
@@ -27,20 +23,6 @@ export const BalanceManager = ({ children }: BalanceManagerProps) => {
|
||||
const { updateBalances: updateStoreBalances } = useBalances();
|
||||
const { config } = useEthereumConfig();
|
||||
|
||||
const numberOfConfirmations = config?.confirmations || 0;
|
||||
|
||||
useListenForAssociationEvents(
|
||||
contracts?.staking.contract,
|
||||
pubKey,
|
||||
numberOfConfirmations
|
||||
);
|
||||
|
||||
useListenForAssociationEvents(
|
||||
contracts?.vesting.contract,
|
||||
pubKey,
|
||||
numberOfConfirmations
|
||||
);
|
||||
|
||||
const getUserTrancheBalances = useGetUserTrancheBalances(
|
||||
account || '',
|
||||
contracts?.vesting
|
||||
@@ -52,7 +34,7 @@ export const BalanceManager = ({ children }: BalanceManagerProps) => {
|
||||
);
|
||||
|
||||
// update balances on connect to Ethereum
|
||||
useEffect(() => {
|
||||
React.useEffect(() => {
|
||||
const updateBalances = async () => {
|
||||
if (!account || !config) return;
|
||||
try {
|
||||
@@ -93,13 +75,13 @@ export const BalanceManager = ({ children }: BalanceManagerProps) => {
|
||||
]);
|
||||
|
||||
// This use effect hook is very expensive and is kept separate to prevent expensive reloading of data.
|
||||
useEffect(() => {
|
||||
React.useEffect(() => {
|
||||
if (account) {
|
||||
getUserTrancheBalances();
|
||||
}
|
||||
}, [account, getUserTrancheBalances]);
|
||||
|
||||
useEffect(() => {
|
||||
React.useEffect(() => {
|
||||
if (account) {
|
||||
getAssociationBreakdown();
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ export const LockedProgress = ({
|
||||
unlocked,
|
||||
leftLabel,
|
||||
rightLabel,
|
||||
leftColor = Colors.vega.pink.DEFAULT,
|
||||
rightColor = Colors.vega.green.DEFAULT,
|
||||
leftColor = Colors.vega.pink,
|
||||
rightColor = Colors.vega.green,
|
||||
decimals = 2,
|
||||
}: LockedProgressProps) => {
|
||||
const lockedPercentage = React.useMemo(() => {
|
||||
|
||||
@@ -18,7 +18,7 @@ export const NavDropDown = ({ navbarTheme }: { navbarTheme: NavbarTheme }) => {
|
||||
<AppNavLink
|
||||
name={
|
||||
<NavDropdownMenuTrigger
|
||||
className="w-auto flex items-center"
|
||||
className="w-auto text-capMenu"
|
||||
data-testid="state-trigger"
|
||||
onClick={() => setOpen(!isOpen)}
|
||||
>
|
||||
@@ -38,7 +38,6 @@ export const NavDropDown = ({ navbarTheme }: { navbarTheme: NavbarTheme }) => {
|
||||
name={t(r.name)}
|
||||
path={r.path}
|
||||
navbarTheme={'inherit'}
|
||||
subNav={true}
|
||||
end={true}
|
||||
fullWidth={true}
|
||||
/>
|
||||
|
||||
@@ -13,7 +13,6 @@ interface AppNavLinkProps {
|
||||
target?: HTMLAttributeAnchorTarget;
|
||||
end?: boolean;
|
||||
fullWidth?: boolean;
|
||||
subNav?: boolean;
|
||||
}
|
||||
|
||||
export const AppNavLink = ({
|
||||
@@ -24,32 +23,28 @@ export const AppNavLink = ({
|
||||
testId,
|
||||
end = false,
|
||||
fullWidth = false,
|
||||
subNav = false,
|
||||
}: AppNavLinkProps) => {
|
||||
const borderClasses = classNames(
|
||||
'absolute h-0.5 w-full bottom-[-1px] left-0',
|
||||
{
|
||||
'bg-black dark:bg-vega-yellow': navbarTheme !== 'yellow',
|
||||
'bg-black': navbarTheme === 'yellow',
|
||||
}
|
||||
);
|
||||
const borderClasses = classNames('absolute h-1 w-full bottom-[-1px] left-0', {
|
||||
'bg-black dark:bg-vega-yellow': navbarTheme !== 'yellow',
|
||||
'bg-black': navbarTheme === 'yellow',
|
||||
});
|
||||
return (
|
||||
<NavLink
|
||||
key={path}
|
||||
data-testid={testId}
|
||||
to={{ pathname: path }}
|
||||
className={getNavLinkClassNames(navbarTheme, fullWidth, subNav)}
|
||||
className={getNavLinkClassNames(navbarTheme, fullWidth)}
|
||||
target={target}
|
||||
end={end}
|
||||
>
|
||||
{({ isActive }) => {
|
||||
return (
|
||||
<div className={subNav ? 'inline-block relative pb-1' : undefined}>
|
||||
<>
|
||||
{name}
|
||||
{isActive && (
|
||||
<span data-testid="link-active" className={borderClasses} />
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</NavLink>
|
||||
|
||||
@@ -22,8 +22,9 @@ const renderComponent = (initialEntries?: string[]) => {
|
||||
};
|
||||
|
||||
describe('nav', () => {
|
||||
it('Renders logo with link to home', () => {
|
||||
it('Renders title and logo with link to home', () => {
|
||||
renderComponent();
|
||||
expect(screen.getByText('Governance')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('logo-link')).toHaveProperty(
|
||||
'href',
|
||||
'http://localhost/'
|
||||
|
||||
@@ -3,8 +3,7 @@ import { NetworkSwitcher } from '@vegaprotocol/environment';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { TOP_LEVEL_ROUTES } from '../../routes/routes';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import logoWhiteText from '../../images/logo-white-text.png';
|
||||
import logoBlackText from '../../images/logo-black-text.png';
|
||||
import vegaWhite from '../../images/vega_white.png';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { NavDrawer } from './nav-draw';
|
||||
import { Nav as ToolkitNav } from '@vegaprotocol/ui-toolkit';
|
||||
@@ -47,19 +46,14 @@ export const Nav = ({ navbarTheme = 'inherit' }: NavbarProps) => {
|
||||
navbarTheme={navbarTheme}
|
||||
icon={
|
||||
<Link to="/" data-testid="logo-link">
|
||||
<img
|
||||
alt="Vega"
|
||||
src={navbarTheme === 'yellow' ? logoBlackText : logoWhiteText}
|
||||
height={30}
|
||||
width={250}
|
||||
/>
|
||||
<img alt="Vega" src={vegaWhite} height={30} width={30} />
|
||||
</Link>
|
||||
}
|
||||
title={undefined}
|
||||
title={t('Governance')}
|
||||
titleContent={<NetworkSwitcher />}
|
||||
>
|
||||
{isDesktop ? (
|
||||
<nav className="flex items-center flex-1 px-4">
|
||||
<nav className="flex items-center flex-1 px-2">
|
||||
{TOP_LEVEL_ROUTES.map((r) => (
|
||||
<AppNavLink
|
||||
key={r.path}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import classNames from 'classnames';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface AppLayoutProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
export const AppLayout = ({ children }: AppLayoutProps) => {
|
||||
const { isReadOnly } = useVegaWallet();
|
||||
const AppLayoutClasses = classNames(
|
||||
'app w-full max-w-[1500px] mx-auto grid min-h-full',
|
||||
'border-neutral-700 lg:border-l lg:border-r',
|
||||
'lg:text-body-large',
|
||||
{
|
||||
'grid-rows-[repeat(2,min-content)_1fr_min-content]': !isReadOnly,
|
||||
'grid-rows-[repeat(3,min-content)_1fr_min-content]': isReadOnly,
|
||||
}
|
||||
);
|
||||
|
||||
return <div className={AppLayoutClasses}>{children}</div>;
|
||||
};
|
||||
@@ -1,9 +1,5 @@
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import {
|
||||
ViewingAsBanner,
|
||||
AnnouncementBanner,
|
||||
ExternalLink,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import React from 'react';
|
||||
|
||||
@@ -19,18 +15,12 @@ export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
|
||||
const { isReadOnly, pubKey, disconnect } = useVegaWallet();
|
||||
return (
|
||||
<>
|
||||
<AnnouncementBanner>
|
||||
<div className="font-alpha calt uppercase text-center text-lg text-white">
|
||||
<span className="pr-4">The Mainnet sims are live!</span>
|
||||
<ExternalLink href="https://fairground.wtf/">
|
||||
Come help stress test the network
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</AnnouncementBanner>
|
||||
<Nav navbarTheme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'} />
|
||||
{isReadOnly ? (
|
||||
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
|
||||
) : null}
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="w-full border-b border-neutral-700 lg:grid lg:grid-rows-[1fr] lg:grid-cols-[1fr_450px]">
|
||||
<main className="col-start-1 p-4">{children}</main>
|
||||
<aside className="col-start-2 row-start-1 row-span-2 hidden lg:block p-4 bg-banner bg-contain border-l border-neutral-700">
|
||||
|
||||
@@ -25,8 +25,6 @@ import { usePollForDelegations } from './hooks';
|
||||
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import { Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { toBigNum } from '@vegaprotocol/react-helpers';
|
||||
import { usePendingBalancesStore } from '../../hooks/use-pending-balances-manager';
|
||||
import { StakingEventType } from '../../hooks/use-get-association-breakdown';
|
||||
|
||||
export const VegaWallet = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -121,10 +119,6 @@ interface VegaWalletConnectedProps {
|
||||
}
|
||||
|
||||
const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
||||
const pendingBalances = usePendingBalancesStore(
|
||||
(state) => state.pendingBalances
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
appDispatch,
|
||||
@@ -132,27 +126,6 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
||||
} = useAppState();
|
||||
const { delegations, currentStakeAvailable, delegatedNodes, accounts } =
|
||||
usePollForDelegations();
|
||||
const amountRemoved = BigNumber.sum.apply(null, [
|
||||
new BigNumber(0),
|
||||
...pendingBalances
|
||||
.filter(({ event }) => event === StakingEventType.Stake_Removed)
|
||||
.map(({ args }) => toBigNum(args?.[1].toString(), decimals)),
|
||||
]);
|
||||
|
||||
const amountAdded = BigNumber.sum.apply(null, [
|
||||
new BigNumber(0),
|
||||
...pendingBalances
|
||||
.filter(({ event }) => event === StakingEventType.Stake_Deposited)
|
||||
.map(({ args }) => toBigNum(args?.[1].toString(), decimals)),
|
||||
]);
|
||||
const totalPending = React.useMemo(
|
||||
() => amountRemoved.plus(amountAdded),
|
||||
[amountAdded, amountRemoved]
|
||||
);
|
||||
const pendingStakeAmount = React.useMemo(
|
||||
() => currentStakeAvailable.plus(amountAdded).minus(amountRemoved),
|
||||
[amountAdded, amountRemoved, currentStakeAvailable]
|
||||
);
|
||||
|
||||
const unstaked = React.useMemo(() => {
|
||||
const totalDelegated = delegations.reduce<BigNumber>(
|
||||
@@ -188,26 +161,6 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
||||
symbol="VEGA"
|
||||
balance={currentStakeAvailable}
|
||||
/>
|
||||
{totalPending.eq(0) ? null : (
|
||||
<>
|
||||
<WalletCardAsset
|
||||
image={vegaWhite}
|
||||
decimals={decimals}
|
||||
name="VEGA"
|
||||
subheading={t('Pending association')}
|
||||
symbol="VEGA"
|
||||
balance={totalPending}
|
||||
/>
|
||||
<WalletCardAsset
|
||||
image={vegaWhite}
|
||||
decimals={decimals}
|
||||
name="VEGA"
|
||||
subheading={t('Total associated after pending')}
|
||||
symbol="VEGA"
|
||||
balance={pendingStakeAmount}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div data-testid="vega-wallet-balance-unstaked">
|
||||
<WalletCardRow label={t('unstaked')} value={unstaked} />
|
||||
</div>
|
||||
|
||||
@@ -30,12 +30,9 @@ export function useAnimateValue(
|
||||
) {
|
||||
elRef.current?.animate(
|
||||
[
|
||||
{ backgroundColor: customColors.vega.pink, color: colors.white },
|
||||
{
|
||||
backgroundColor: customColors.vega.pink.DEFAULT,
|
||||
color: colors.white,
|
||||
},
|
||||
{
|
||||
backgroundColor: customColors.vega.pink.DEFAULT,
|
||||
backgroundColor: customColors.vega.pink,
|
||||
color: colors.white,
|
||||
offset: 0.8,
|
||||
},
|
||||
@@ -56,11 +53,11 @@ export function useAnimateValue(
|
||||
elRef.current?.animate(
|
||||
[
|
||||
{
|
||||
backgroundColor: customColors.vega.green.DEFAULT,
|
||||
backgroundColor: customColors.vega.green,
|
||||
color: colors.white,
|
||||
},
|
||||
{
|
||||
backgroundColor: customColors.vega.green.DEFAULT,
|
||||
backgroundColor: customColors.vega.green,
|
||||
color: colors.white,
|
||||
offset: 0.8,
|
||||
},
|
||||
|
||||
@@ -11,11 +11,6 @@ import { useAppState } from '../contexts/app-state/app-state-context';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { useBalances } from '../lib/balances/balances-store';
|
||||
|
||||
export enum StakingEventType {
|
||||
Stake_Removed = 'Stake_Removed',
|
||||
Stake_Deposited = 'Stake_Deposited',
|
||||
}
|
||||
|
||||
export function useGetAssociationBreakdown(
|
||||
ethAddress: string,
|
||||
staking: StakingBridge,
|
||||
@@ -68,8 +63,8 @@ function combineStakeEventsByVegaKey(
|
||||
const res = events.reduce((obj, e) => {
|
||||
const vegaKey = e.args?.vega_public_key;
|
||||
const amount = parseEventAmount(e, decimals);
|
||||
const isDeposit = e.event === StakingEventType.Stake_Deposited;
|
||||
const isRemove = e.event === StakingEventType.Stake_Removed;
|
||||
const isDeposit = e.event === 'Stake_Deposited';
|
||||
const isRemove = e.event === 'Stake_Removed';
|
||||
|
||||
if (!isDeposit && !isRemove) return obj;
|
||||
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
import { useListenForPendingEthEvents } from './use-listen-for-pending-eth-events';
|
||||
import { renderHook, cleanup, waitFor } from '@testing-library/react';
|
||||
import type { Contract, EventFilter, Event } from 'ethers';
|
||||
|
||||
let contract: Contract;
|
||||
let filter: EventFilter;
|
||||
let addPendingTxs: (event: Event[]) => void;
|
||||
let removePendingTx: (event: Event) => void;
|
||||
let resetPendingTxs: () => void;
|
||||
|
||||
beforeEach(() => {
|
||||
contract = {
|
||||
on: jest.fn(),
|
||||
off: jest.fn(),
|
||||
queryFilter: jest.fn().mockResolvedValue([]),
|
||||
} as unknown as Contract;
|
||||
filter = {} as EventFilter;
|
||||
addPendingTxs = jest.fn();
|
||||
removePendingTx = jest.fn();
|
||||
resetPendingTxs = jest.fn();
|
||||
});
|
||||
|
||||
jest.mock('@web3-react/core', () => ({
|
||||
useWeb3React: () => ({
|
||||
provider: {
|
||||
getBlockNumber: jest.fn().mockResolvedValue(1),
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('useListenForPendingEthEvents', () => {
|
||||
it('listens for events on contract', async () => {
|
||||
renderHook(() =>
|
||||
useListenForPendingEthEvents(
|
||||
1,
|
||||
contract,
|
||||
filter,
|
||||
addPendingTxs,
|
||||
removePendingTx,
|
||||
resetPendingTxs
|
||||
)
|
||||
);
|
||||
|
||||
expect(contract.on).toHaveBeenCalledWith(filter, expect.any(Function));
|
||||
cleanup();
|
||||
expect(contract.off).toHaveBeenCalledWith(filter, expect.any(Function));
|
||||
});
|
||||
|
||||
it('waits for correct number of confirmations before removing tx from pending txs', async () => {
|
||||
renderHook(() => {
|
||||
useListenForPendingEthEvents(
|
||||
2,
|
||||
contract,
|
||||
filter,
|
||||
addPendingTxs,
|
||||
removePendingTx,
|
||||
resetPendingTxs
|
||||
);
|
||||
});
|
||||
|
||||
const listener = (contract.on as jest.Mock).mock.calls[0][1];
|
||||
const event = {
|
||||
getTransaction: jest.fn().mockResolvedValue({
|
||||
wait: jest.fn().mockResolvedValue({}),
|
||||
}),
|
||||
} as unknown as Event;
|
||||
listener(null, null, null, event);
|
||||
|
||||
expect(addPendingTxs).toHaveBeenCalledWith([event]);
|
||||
expect(removePendingTx).not.toHaveBeenCalled();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(removePendingTx).toHaveBeenCalledWith(event);
|
||||
});
|
||||
});
|
||||
|
||||
it('gets existing transactions', async () => {
|
||||
const event = {
|
||||
getTransaction: jest.fn().mockResolvedValue({
|
||||
wait: jest.fn().mockResolvedValue(null),
|
||||
}),
|
||||
} as unknown as Event;
|
||||
|
||||
contract.queryFilter = jest.fn().mockResolvedValue([event]);
|
||||
|
||||
renderHook(() => {
|
||||
useListenForPendingEthEvents(
|
||||
2,
|
||||
contract,
|
||||
filter,
|
||||
addPendingTxs,
|
||||
removePendingTx,
|
||||
resetPendingTxs
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(contract.queryFilter).toHaveBeenCalledWith(filter, -1);
|
||||
expect(addPendingTxs).toHaveBeenCalledWith([event]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,103 +0,0 @@
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import type { Contract, Event, EventFilter } from 'ethers';
|
||||
|
||||
export const useListenForPendingEthEvents = (
|
||||
numberOfConfirmations: number,
|
||||
contract: Contract | undefined,
|
||||
filter: EventFilter | null,
|
||||
addPendingTxs: (event: Event[]) => void,
|
||||
removePendingTx: (event: Event) => void,
|
||||
resetPendingTxs: () => void
|
||||
) => {
|
||||
const { provider } = useWeb3React();
|
||||
|
||||
/**
|
||||
* Add listener for the ethereum events on the contract passed in for the filter passed in.
|
||||
* Push the event into the store and wait for the correct number of confirmations before removing it.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!contract || !filter) {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const listener = async (...args: any[]) => {
|
||||
try {
|
||||
const event = args[3] as Event;
|
||||
addPendingTxs([event]);
|
||||
const tx = await event.getTransaction();
|
||||
await tx.wait(numberOfConfirmations);
|
||||
removePendingTx(event);
|
||||
} catch (e) {
|
||||
Sentry.captureException(`Error listening for pending eth events ${e}`);
|
||||
}
|
||||
};
|
||||
|
||||
contract.on(filter, listener);
|
||||
|
||||
return () => {
|
||||
contract.off(filter, listener);
|
||||
};
|
||||
}, [addPendingTxs, contract, filter, numberOfConfirmations, removePendingTx]);
|
||||
|
||||
/**
|
||||
* Get all transactions that exist on the blockchain but have yet to reach the number of confirmations
|
||||
*/
|
||||
const getExistingTransactions = useCallback(async () => {
|
||||
const blockNumber = (await provider?.getBlockNumber()) || 0;
|
||||
if (!filter || !contract) {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
return await contract.queryFilter(
|
||||
filter,
|
||||
blockNumber - numberOfConfirmations
|
||||
);
|
||||
} catch (e) {
|
||||
Sentry.captureException(`Error getting existing transactions ${e}`);
|
||||
return [];
|
||||
}
|
||||
}, [contract, filter, numberOfConfirmations, provider]);
|
||||
|
||||
const waitForExistingTransactions = useCallback(
|
||||
(events: Event[], numberOfConfirmations: number) => {
|
||||
events.map(async (event) => {
|
||||
try {
|
||||
const tx = await event.getTransaction();
|
||||
|
||||
await tx.wait(Math.max(numberOfConfirmations, 0));
|
||||
|
||||
removePendingTx(event);
|
||||
} catch (e) {
|
||||
Sentry.captureException(
|
||||
`Error waiting for existing transactions ${e}`
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
[removePendingTx]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
resetPendingTxs();
|
||||
getExistingTransactions().then((events) => {
|
||||
if (!cancelled) {
|
||||
addPendingTxs([...events]);
|
||||
waitForExistingTransactions([...events], numberOfConfirmations);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [
|
||||
addPendingTxs,
|
||||
getExistingTransactions,
|
||||
numberOfConfirmations,
|
||||
resetPendingTxs,
|
||||
waitForExistingTransactions,
|
||||
]);
|
||||
};
|
||||
@@ -1,56 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
import { usePendingBalancesStore } from './use-pending-balances-manager';
|
||||
import type { Contract } from 'ethers';
|
||||
import { useListenForPendingEthEvents } from './use-listen-for-pending-eth-events';
|
||||
import { prepend0x } from '@vegaprotocol/smart-contracts';
|
||||
|
||||
export const useListenForStakingEvents = (
|
||||
contract: Contract | undefined,
|
||||
vegaPublicKey: string | null,
|
||||
numberOfConfirmations: number
|
||||
) => {
|
||||
const { addPendingTxs, removePendingTx, resetPendingTxs } =
|
||||
usePendingBalancesStore((state) => ({
|
||||
addPendingTxs: state.addPendingTxs,
|
||||
removePendingTx: state.removePendingTx,
|
||||
resetPendingTxs: state.resetPendingTxs,
|
||||
}));
|
||||
const addFilter = useMemo(
|
||||
() =>
|
||||
vegaPublicKey && contract
|
||||
? contract.filters.Stake_Deposited(null, null, prepend0x(vegaPublicKey))
|
||||
: null,
|
||||
[contract, vegaPublicKey]
|
||||
);
|
||||
const removeFilter = useMemo(
|
||||
() =>
|
||||
vegaPublicKey && contract
|
||||
? contract.filters.Stake_Removed(null, null, prepend0x(vegaPublicKey))
|
||||
: null,
|
||||
[contract, vegaPublicKey]
|
||||
);
|
||||
|
||||
/**
|
||||
* Listen for all add stake events
|
||||
*/
|
||||
useListenForPendingEthEvents(
|
||||
numberOfConfirmations,
|
||||
contract,
|
||||
addFilter,
|
||||
addPendingTxs,
|
||||
removePendingTx,
|
||||
resetPendingTxs
|
||||
);
|
||||
|
||||
/**
|
||||
* Listen for all remove stake events
|
||||
*/
|
||||
useListenForPendingEthEvents(
|
||||
numberOfConfirmations,
|
||||
contract,
|
||||
removeFilter,
|
||||
addPendingTxs,
|
||||
removePendingTx,
|
||||
resetPendingTxs
|
||||
);
|
||||
};
|
||||
@@ -1,76 +0,0 @@
|
||||
import { act } from '@testing-library/react-hooks';
|
||||
import { usePendingBalancesStore } from './use-pending-balances-manager';
|
||||
import type { Event } from 'ethers';
|
||||
|
||||
afterEach(() => {
|
||||
usePendingBalancesStore.setState((state) => ({
|
||||
...state,
|
||||
pendingBalances: [],
|
||||
}));
|
||||
});
|
||||
|
||||
const event1 = { transactionHash: 'tx1' } as Event;
|
||||
const event2 = { transactionHash: 'tx2' } as Event;
|
||||
|
||||
describe('usePendingBalancesStore', () => {
|
||||
it('should add new events to the pendingBalances state and remove duplicates', () => {
|
||||
const { addPendingTxs } = usePendingBalancesStore.getState();
|
||||
const duplicateEvent = { transactionHash: 'tx1' } as Event;
|
||||
|
||||
act(() => {
|
||||
addPendingTxs([event1, duplicateEvent]);
|
||||
});
|
||||
|
||||
expect(usePendingBalancesStore.getState().pendingBalances).toEqual([
|
||||
event1,
|
||||
]);
|
||||
|
||||
act(() => {
|
||||
addPendingTxs([event2]);
|
||||
});
|
||||
|
||||
expect(usePendingBalancesStore.getState().pendingBalances).toEqual([
|
||||
event1,
|
||||
event2,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should remove a specific event from the pendingBalances state', () => {
|
||||
const { addPendingTxs, removePendingTx } =
|
||||
usePendingBalancesStore.getState();
|
||||
const eventToRemove = { transactionHash: 'tx1' } as Event;
|
||||
|
||||
act(() => {
|
||||
addPendingTxs([eventToRemove, event2]);
|
||||
});
|
||||
expect(usePendingBalancesStore.getState().pendingBalances).toEqual([
|
||||
eventToRemove,
|
||||
event2,
|
||||
]);
|
||||
|
||||
act(() => {
|
||||
removePendingTx(eventToRemove);
|
||||
});
|
||||
expect(usePendingBalancesStore.getState().pendingBalances).toEqual([
|
||||
event2,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should reset the pendingBalances state', () => {
|
||||
const { addPendingTxs, resetPendingTxs } =
|
||||
usePendingBalancesStore.getState();
|
||||
|
||||
act(() => {
|
||||
addPendingTxs([event1, event2]);
|
||||
});
|
||||
expect(usePendingBalancesStore.getState().pendingBalances).toEqual([
|
||||
event1,
|
||||
event2,
|
||||
]);
|
||||
|
||||
act(() => {
|
||||
resetPendingTxs();
|
||||
});
|
||||
expect(usePendingBalancesStore.getState().pendingBalances).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
import type { Event } from 'ethers';
|
||||
import uniqBy from 'lodash/uniqBy';
|
||||
|
||||
import create from 'zustand';
|
||||
|
||||
export type PendingTxsStore = {
|
||||
pendingBalances: Event[];
|
||||
addPendingTxs: (event: Event[]) => void;
|
||||
removePendingTx: (event: Event) => void;
|
||||
resetPendingTxs: () => void;
|
||||
};
|
||||
|
||||
export const usePendingBalancesStore = create<PendingTxsStore>((set, get) => ({
|
||||
pendingBalances: [],
|
||||
addPendingTxs: (event: Event[]) => {
|
||||
set({
|
||||
pendingBalances: uniqBy(
|
||||
[...get().pendingBalances, ...event],
|
||||
'transactionHash'
|
||||
),
|
||||
});
|
||||
},
|
||||
removePendingTx: (event: Event) => {
|
||||
set({
|
||||
pendingBalances: [
|
||||
...get().pendingBalances.filter(
|
||||
({ transactionHash }) => transactionHash !== event.transactionHash
|
||||
),
|
||||
],
|
||||
});
|
||||
},
|
||||
resetPendingTxs: () => {
|
||||
set({ pendingBalances: [] });
|
||||
},
|
||||
}));
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.7 KiB |
@@ -102,7 +102,7 @@ export const VoteDetails = ({
|
||||
</table>
|
||||
</section>
|
||||
)}
|
||||
<section data-testid="votes-table">
|
||||
<section>
|
||||
<SubHeading title={t('tokenVotes')} />
|
||||
<p>
|
||||
<span>
|
||||
|
||||
@@ -177,7 +177,7 @@ interface TotalPenaltiesRendererProps {
|
||||
performanceScore: string;
|
||||
performancePenalty: string;
|
||||
overstakedAmount: string;
|
||||
overstakingPenalty: string;
|
||||
overstakedPenalty: string;
|
||||
totalPenalties: string;
|
||||
};
|
||||
}
|
||||
@@ -192,10 +192,20 @@ export const TotalPenaltiesRenderer = ({
|
||||
description={
|
||||
<>
|
||||
<div>
|
||||
{t('performancePenalty')}: {data.performancePenalty}
|
||||
<span>
|
||||
{t('performancePenalty')}: {data.performancePenalty}
|
||||
</span>
|
||||
<span className="pl-2">
|
||||
({t('score')} {data.performanceScore})
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
{t('overstakedPenalty')}: {data.overstakingPenalty}
|
||||
<span>
|
||||
{t('overstakedPenalty')}: {data.overstakedPenalty}
|
||||
</span>
|
||||
<span className="pl-2">
|
||||
({t('overstaked')} {data.overstakedAmount})
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
{t('totalPenalties')}:{' '}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Dialog, Icon, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Routes from '../../routes';
|
||||
import type { StakeAction } from './staking-form';
|
||||
import { Actions, RemoveType } from './staking-form';
|
||||
@@ -23,7 +23,6 @@ export const StakeSuccess = ({
|
||||
toggleDialog,
|
||||
}: StakeSuccessProps) => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const isAdd = action === Actions.Add;
|
||||
const title = isAdd
|
||||
? t('stakeAddSuccessTitle', { amount })
|
||||
@@ -45,15 +44,7 @@ export const StakeSuccess = ({
|
||||
<div>
|
||||
<p>{message}</p>
|
||||
<p>
|
||||
<Link
|
||||
className="underline"
|
||||
to={Routes.VALIDATORS}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
toggleDialog();
|
||||
setTimeout(() => navigate(Routes.VALIDATORS), 0);
|
||||
}}
|
||||
>
|
||||
<Link className="underline" to={Routes.VALIDATORS}>
|
||||
{t('backToStaking')}
|
||||
</Link>
|
||||
</p>
|
||||
|
||||
@@ -29,7 +29,7 @@ export const TrancheProgress = ({
|
||||
<span className="tranches__progress-title">{t('Locked')}</span>
|
||||
<ProgressBar
|
||||
width={220}
|
||||
color={Colors.vega.pink.DEFAULT}
|
||||
color={Colors.vega.pink}
|
||||
percentage={lockedPercentage}
|
||||
/>
|
||||
<span className="tranches__progress-numbers">
|
||||
@@ -40,7 +40,7 @@ export const TrancheProgress = ({
|
||||
<span className="tranches__progress-title">{t('Redeemed')}</span>
|
||||
<ProgressBar
|
||||
width={220}
|
||||
color={Colors.vega.green.DEFAULT}
|
||||
color={Colors.vega.green}
|
||||
percentage={removedPercentage}
|
||||
/>
|
||||
<span className="tranches__progress-numbers">
|
||||
|
||||
@@ -34,10 +34,10 @@ export const VestingChart = () => {
|
||||
<AreaChart data={data}>
|
||||
<defs>
|
||||
{[
|
||||
['pink', Colors.vega.pink.DEFAULT],
|
||||
['green', Colors.vega.green.DEFAULT],
|
||||
['pink', Colors.vega.pink],
|
||||
['green', Colors.vega.green],
|
||||
['orange', Colors.warning],
|
||||
['yellow', Colors.vega.yellow.DEFAULT],
|
||||
['yellow', Colors.vega.yellow],
|
||||
].map(([key, color]) => (
|
||||
<linearGradient key={key} id={key} x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stopColor={color} stopOpacity={0.85} />
|
||||
@@ -97,7 +97,7 @@ export const VestingChart = () => {
|
||||
dot={false}
|
||||
type="linear"
|
||||
dataKey="team"
|
||||
stroke={Colors.vega.pink.DEFAULT}
|
||||
stroke={Colors.vega.pink}
|
||||
fill="url(#pink)"
|
||||
yAxisId={0}
|
||||
strokeWidth={2}
|
||||
@@ -109,7 +109,7 @@ export const VestingChart = () => {
|
||||
dot={false}
|
||||
type="monotone"
|
||||
dataKey="earlyInvestors"
|
||||
stroke={Colors.vega.green.DEFAULT}
|
||||
stroke={Colors.vega.green}
|
||||
fill="url(#green)"
|
||||
yAxisId={0}
|
||||
strokeWidth={2}
|
||||
@@ -121,7 +121,7 @@ export const VestingChart = () => {
|
||||
dot={false}
|
||||
type="monotone"
|
||||
dataKey="publicSale"
|
||||
stroke={Colors.vega.yellow.DEFAULT}
|
||||
stroke={Colors.vega.yellow}
|
||||
fill="url(#yellow)"
|
||||
yAxisId={0}
|
||||
strokeWidth={2}
|
||||
|
||||
@@ -13,9 +13,3 @@
|
||||
@apply mb-2 text-neutral-400;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.border-default {
|
||||
@apply border-vega-dark-200;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,7 @@ const txTimeout = Cypress.env('txTimeout');
|
||||
const sepoliaUrl = Cypress.env('ETHERSCAN_URL');
|
||||
const btcName =
|
||||
'BTC (local)5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c - tBTC';
|
||||
const vegaName =
|
||||
'Vegab4f2726571fbe8e33b442dc92ed2d7f0d810e21835b7371a7915a365f07ccd9b - VEGA';
|
||||
const btcSymbol = 'tBTC';
|
||||
const vegaSymbol = 'VEGA';
|
||||
const usdcSymbol = 'fUSDC';
|
||||
const toastContent = 'toast-content';
|
||||
const ordersTab = 'Orders';
|
||||
@@ -36,112 +33,9 @@ const toastCloseBtn = 'toast-close';
|
||||
const price = '390';
|
||||
const size = '0.0005';
|
||||
const newPrice = '200';
|
||||
const completeWithdrawalBtn = 'complete-withdrawal';
|
||||
|
||||
// TODO: ensure this test runs only if capsule is running via workflow
|
||||
// Because the tests are run on a live network to optimize time, the tests are interdependent and must be run in the given order.
|
||||
describe('capsule - without MultiSign', { tags: '@slow' }, () => {
|
||||
before(() => {
|
||||
cy.createMarket();
|
||||
cy.get('@markets').then((markets) => {
|
||||
cy.wrap(markets[0]).as('market');
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('can deposit', function () {
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
|
||||
// 1001-DEPO-001
|
||||
// 1001-DEPO-002
|
||||
// 1001-DEPO-003
|
||||
// 1001-DEPO-005
|
||||
// 1001-DEPO-006
|
||||
// 1001-DEPO-007
|
||||
// 1001-DEPO-008
|
||||
// 1001-DEPO-009
|
||||
// 1001-DEPO-010
|
||||
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
connectEthereumWallet('Unknown');
|
||||
cy.get(assetSelectField, txTimeout).select(btcName, { force: true });
|
||||
cy.getByTestId('deposit-approve-submit').click();
|
||||
cy.getByTestId('dialog-title').should('contain.text', 'Approve complete');
|
||||
cy.get('[data-testid="Return to deposit"]').click();
|
||||
cy.get(amountField).clear().type('10');
|
||||
cy.getByTestId('deposit-submit').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
'contain.text',
|
||||
`Transaction confirmedYour transaction has been confirmed.View on EtherscanDeposit 10.00 ${btcSymbol}`,
|
||||
{ matchCase: false }
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
cy.getByTestId('Collateral').click();
|
||||
|
||||
cy.highlight('deposit verification');
|
||||
|
||||
cy.getByTestId('asset', txTimeout).should('contain.text', btcSymbol);
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.get('.ag-cell-value', txTimeout).should('contain.text', btcSymbol);
|
||||
cy.get('[col-id="status"]').should('not.have.text', 'Open', txTimeout);
|
||||
|
||||
cy.get('[col-id="txHash"]')
|
||||
.should('have.length.above', 2)
|
||||
.eq(1)
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get('[col-id="asset.symbol"]').should('have.text', btcSymbol);
|
||||
cy.get('[col-id="amount"]').should('have.text', '10.00');
|
||||
cy.get('[col-id="createdTimestamp"]').should('not.be.empty');
|
||||
cy.get('[col-id="status"]').should('have.text', 'Finalized');
|
||||
cy.get('[col-id="txHash"]')
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', `${sepoliaUrl}/tx/0x`);
|
||||
});
|
||||
});
|
||||
|
||||
it('can not withdrawal because of no MultiSign', function () {
|
||||
// 1002-WITH-022
|
||||
// 1002-WITH-023
|
||||
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
cy.getByTestId('withdraw-dialog-button').click();
|
||||
cy.get(assetSelectField, txTimeout).select(btcName, { force: true });
|
||||
cy.get(amountField).clear().type('1');
|
||||
cy.getByTestId('submit-withdrawal').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
'contain.text',
|
||||
'Funds unlocked'
|
||||
);
|
||||
|
||||
cy.getByTestId('tab-withdrawals').within(() => {
|
||||
cy.get('.ag-center-cols-container')
|
||||
.children()
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get('[col-id="status"]').should('contain.text', 'Pending');
|
||||
});
|
||||
});
|
||||
|
||||
cy.highlight('withdrawals verification');
|
||||
cy.getByTestId('toast-complete-withdrawal').click();
|
||||
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
'contain.text',
|
||||
'Error occurredprocessing response error'
|
||||
);
|
||||
cy.getByTestId(completeWithdrawalBtn).should(
|
||||
'contain.text',
|
||||
'Complete withdrawal'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('capsule', { tags: '@slow' }, () => {
|
||||
before(() => {
|
||||
cy.createMarket();
|
||||
@@ -234,15 +128,13 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
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',
|
||||
`ConfirmedYour 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(ordersTab).click();
|
||||
cy.getByTestId(toastCloseBtn).click({ multiple: true });
|
||||
cy.get('.ag-center-cols-container')
|
||||
.children()
|
||||
.first()
|
||||
@@ -272,8 +164,62 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
.should('contain.text', OrderStatusMapping.STATUS_CANCELLED);
|
||||
});
|
||||
|
||||
it('can deposit', function () {
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
|
||||
// 1001-DEPO-001
|
||||
// 1001-DEPO-002
|
||||
// 1001-DEPO-003
|
||||
// 1001-DEPO-005
|
||||
// 1001-DEPO-006
|
||||
// 1001-DEPO-007
|
||||
// 1001-DEPO-008
|
||||
// 1001-DEPO-009
|
||||
// 1001-DEPO-010
|
||||
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
connectEthereumWallet('Unknown');
|
||||
cy.get(assetSelectField, txTimeout).select(btcName, { force: true });
|
||||
cy.getByTestId('deposit-approve-submit').click();
|
||||
cy.getByTestId('dialog-title').should('contain.text', 'Approve complete');
|
||||
cy.get('[data-testid="Return to deposit"]').click();
|
||||
cy.get(amountField).clear().type('1');
|
||||
cy.getByTestId('deposit-submit').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
'contain.text',
|
||||
`Transaction confirmedYour transaction has been confirmed.View on EtherscanDeposit 1.00 ${btcSymbol}`,
|
||||
{ matchCase: false }
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
cy.getByTestId('Collateral').click();
|
||||
|
||||
cy.highlight('deposit verification');
|
||||
|
||||
cy.getByTestId('asset', txTimeout).should('contain.text', btcSymbol);
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.get('.ag-cell-value', txTimeout).should('contain.text', btcSymbol);
|
||||
cy.get('[col-id="status"]').should('not.have.text', 'Open', txTimeout);
|
||||
|
||||
cy.get('[col-id="txHash"]')
|
||||
.should('have.length.above', 2)
|
||||
.eq(1)
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get('[col-id="asset.symbol"]').should('have.text', btcSymbol);
|
||||
cy.get('[col-id="amount"]').should('have.text', '1.00');
|
||||
cy.get('[col-id="createdTimestamp"]').should('not.be.empty');
|
||||
cy.get('[col-id="status"]').should('have.text', 'Finalized');
|
||||
cy.get('[col-id="txHash"]')
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', `${sepoliaUrl}/tx/0x`);
|
||||
});
|
||||
});
|
||||
|
||||
it('can withdrawal', function () {
|
||||
// 1002-WITH-0014
|
||||
// 1002-WITH-001
|
||||
// 1002-WITH-006
|
||||
// 1002-WITH-009
|
||||
// 1002-WITH-011
|
||||
@@ -283,18 +229,14 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
// 1002-WITH-014
|
||||
// 1002-WITH-015
|
||||
// 1002-WITH-016
|
||||
// 1002-WITH-017
|
||||
// 1002-WITH-019
|
||||
// 1002-WITH-020
|
||||
// 1002-WITH-021
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
cy.getByTestId('withdraw-dialog-button').click();
|
||||
connectEthereumWallet('Unknown');
|
||||
cy.get(assetSelectField, txTimeout).select(btcName, { force: true });
|
||||
cy.get(assetSelectField, txTimeout).select(
|
||||
'BTC (local)5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c - tBTC',
|
||||
{ force: true }
|
||||
);
|
||||
cy.get(amountField).clear().type('1');
|
||||
cy.getByTestId('submit-withdrawal').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
@@ -313,13 +255,12 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
|
||||
cy.highlight('withdrawals verification');
|
||||
cy.getByTestId('toast-complete-withdrawal').click();
|
||||
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
'contain.text',
|
||||
'Transaction confirmed'
|
||||
);
|
||||
|
||||
cy.getByTestId(completeWithdrawalBtn).eq(0, txTimeout).should('not.exist');
|
||||
cy.getByTestId('complete-withdrawal', txTimeout).should('not.exist');
|
||||
|
||||
cy.get('[col-id="txHash"]', txTimeout)
|
||||
.should('have.length.above', 1)
|
||||
@@ -340,12 +281,9 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', `${sepoliaUrl}/tx/0x`);
|
||||
});
|
||||
// comment because of bug #2819
|
||||
// cy.getByTestId('withdraw-dialog-button').click();
|
||||
// cy.getByTestId('BALANCE_AVAILABLE_value').should('have.text', '0')
|
||||
});
|
||||
|
||||
it('approved amount is less than deposit', function () {
|
||||
it('deposit - if approved amount is less than deposit: must see that an approval is needed and be prompted to approve more', function () {
|
||||
// 1001-DEPO-006
|
||||
|
||||
cy.getByTestId(depositsTab).click();
|
||||
@@ -354,67 +292,6 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
cy.get(amountField).clear().type('20000000');
|
||||
cy.getByTestId('deposit-approve-submit').should('be.visible');
|
||||
});
|
||||
|
||||
it('withdraw - delay verification', function () {
|
||||
// 1001-DEPO-007
|
||||
// 1001-DEPO-024
|
||||
|
||||
cy.visit('/#/portfolio');
|
||||
cy.get('main[data-testid="/portfolio"]').should('exist');
|
||||
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.getByTestId('deposit-button').click();
|
||||
connectEthereumWallet('Unknown');
|
||||
cy.get(assetSelectField, txTimeout).select(vegaName, { force: true });
|
||||
cy.getByTestId('deposit-approve-submit').click();
|
||||
cy.getByTestId('dialog-title').should('contain.text', 'Approve complete');
|
||||
cy.get('[data-testid="Return to deposit"]').click();
|
||||
cy.get(amountField).clear().type('10000');
|
||||
cy.getByTestId('deposit-submit').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
'contain.text',
|
||||
`Your transaction has been confirmed.`,
|
||||
{ matchCase: false }
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
cy.getByTestId('Collateral').click();
|
||||
|
||||
cy.highlight('deposit verification');
|
||||
|
||||
cy.getByTestId('asset', txTimeout).should('contain.text', vegaSymbol);
|
||||
cy.getByTestId(depositsTab).click();
|
||||
cy.get('.ag-cell-value', txTimeout).should('contain.text', vegaSymbol);
|
||||
cy.get('[col-id="status"]').should('not.have.text', 'Open', txTimeout);
|
||||
|
||||
cy.get('[col-id="txHash"]')
|
||||
.should('have.length.above', 2)
|
||||
.eq(1)
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get('[col-id="asset.symbol"]').should('have.text', vegaSymbol);
|
||||
cy.get('[col-id="amount"]').should('have.text', '10,000.00');
|
||||
cy.get('[col-id="createdTimestamp"]').should('not.be.empty');
|
||||
cy.get('[col-id="status"]').should('have.text', 'Finalized');
|
||||
cy.get('[col-id="txHash"]')
|
||||
.find('a')
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', `${sepoliaUrl}/tx/0x`);
|
||||
});
|
||||
|
||||
cy.getByTestId('Withdrawals').click();
|
||||
cy.getByTestId('withdraw-dialog-button').click();
|
||||
cy.get(assetSelectField, txTimeout).select(vegaName, { force: true });
|
||||
cy.get(amountField).clear().type('10000');
|
||||
cy.getByTestId('DELAY_TIME_value').should('have.text', '5 days');
|
||||
cy.getByTestId('submit-withdrawal').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
'contain.text',
|
||||
'Your funds have been unlocked'
|
||||
);
|
||||
cy.getByTestId(toastCloseBtn).click();
|
||||
cy.getByTestId(completeWithdrawalBtn).first().should('be.visible').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should('contain.text', 'Delayed');
|
||||
});
|
||||
});
|
||||
|
||||
function checkIfDataAndTimeOfCreationAndUpdateIsEqual(date: string) {
|
||||
|
||||
@@ -4,7 +4,6 @@ const marketInfoBtn = 'Info';
|
||||
const row = 'key-value-table-row';
|
||||
const marketTitle = 'accordion-title';
|
||||
const externalLink = 'external-link';
|
||||
const accordionContent = 'accordion-content';
|
||||
|
||||
describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
before(() => {
|
||||
@@ -180,8 +179,7 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
'termination.BTC.value'
|
||||
);
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.find(`[data-testid="${externalLink}"]`)
|
||||
cy.getByTestId(externalLink)
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/oracles');
|
||||
});
|
||||
@@ -189,14 +187,12 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
it('proposal displayed', () => {
|
||||
cy.getByTestId(marketTitle).contains('Proposal').click();
|
||||
|
||||
cy.getByTestId(accordionContent)
|
||||
.find(`[data-testid="${externalLink}"]`)
|
||||
cy.getByTestId(externalLink)
|
||||
.first()
|
||||
.should('have.text', 'View governance proposal')
|
||||
.and('have.attr', 'href')
|
||||
.and('contain', '/proposals/market-0');
|
||||
cy.getByTestId(accordionContent)
|
||||
.find(`[data-testid="${externalLink}"]`)
|
||||
cy.getByTestId(externalLink)
|
||||
.eq(1)
|
||||
.should('have.text', 'Propose a change to market')
|
||||
.and('have.attr', 'href')
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
||||
import { marketQuery } from '@vegaprotocol/mock';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
||||
|
||||
describe('markets table', { tags: '@smoke' }, () => {
|
||||
beforeEach(() => {
|
||||
@@ -104,8 +101,7 @@ describe('markets table', { tags: '@smoke' }, () => {
|
||||
'have.length',
|
||||
10
|
||||
);
|
||||
cy.getByTestId('tab-proposed-markets')
|
||||
.find('[data-testid="external-link"]')
|
||||
cy.getByTestId('external-link')
|
||||
.should('have.length', 11)
|
||||
.last()
|
||||
.should('have.text', 'Propose a new market')
|
||||
@@ -115,53 +111,6 @@ describe('markets table', { tags: '@smoke' }, () => {
|
||||
`${Cypress.env('VEGA_TOKEN_URL')}/proposals/propose/new-market`
|
||||
);
|
||||
});
|
||||
|
||||
it('opening auction subsets should be properly displayed', () => {
|
||||
cy.mockTradingPage(
|
||||
Schema.MarketState.STATE_ACTIVE,
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION
|
||||
);
|
||||
cy.mockGQL((req) => {
|
||||
const override = {
|
||||
market: {
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
name: `opening auction MARKET`,
|
||||
},
|
||||
},
|
||||
state: Schema.MarketState.STATE_ACTIVE,
|
||||
tradingMode: Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
||||
},
|
||||
};
|
||||
const market = marketQuery(override);
|
||||
aliasGQLQuery(req, 'Market', market);
|
||||
aliasGQLQuery(req, 'ProposalOfMarket', {
|
||||
proposal: { terms: { enactmentDatetime: '2023-01-31 12:00:01' } },
|
||||
});
|
||||
});
|
||||
cy.visit('/');
|
||||
cy.visit('#/markets/market-0');
|
||||
cy.getByTestId('item-value').contains('Opening auction').realHover();
|
||||
cy.getByTestId('opening-auction-sub-status').should(
|
||||
'contain.text',
|
||||
'Opening auction: Not enough liquidity to open'
|
||||
);
|
||||
|
||||
const now = new Date(Date.parse('2023-01-30 12:00:01')).getTime();
|
||||
cy.clock(now, ['Date']); // Set "now" to BEFORE reservation
|
||||
cy.visit('/');
|
||||
cy.visit('#/markets/market-0');
|
||||
cy.getByTestId('item-value').contains('Opening auction').realHover();
|
||||
cy.getByTestId('opening-auction-sub-status').should(
|
||||
'contain.text',
|
||||
`Opening auction: Closing on ${getDateTimeFormat().format(
|
||||
new Date('2023-01-31 12:00:01')
|
||||
)}`
|
||||
);
|
||||
cy.clock().then((clock) => {
|
||||
clock.restore();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function openMarketDropDown() {
|
||||
|
||||
@@ -452,7 +452,7 @@ describe('limit order validations', { tags: '@smoke' }, () => {
|
||||
//7002-SORD-018
|
||||
cy.getByTestId(orderPriceField)
|
||||
.siblings('label')
|
||||
.should('have.text', 'Price (BTC)');
|
||||
.should('have.text', 'Price (tBTC)');
|
||||
});
|
||||
|
||||
it('must see warning when placing an order with expiry date in past', () => {
|
||||
|
||||
@@ -41,7 +41,6 @@ describe('withdraw form validation', { tags: '@smoke' }, () => {
|
||||
cy.get(toAddressField).should('have.value', ethAddressValue);
|
||||
});
|
||||
it('min amount', () => {
|
||||
// 1002-WITH-010
|
||||
selectAsset(ASSET_SEPOLIA_TBTC);
|
||||
cy.get(amountField).clear().type('0');
|
||||
cy.getByTestId(submitWithdrawBtn).click();
|
||||
@@ -51,8 +50,6 @@ describe('withdraw form validation', { tags: '@smoke' }, () => {
|
||||
);
|
||||
});
|
||||
it('max amount', () => {
|
||||
// 1002-WITH-005
|
||||
// 1002-WITH-008
|
||||
selectAsset(ASSET_EURO); // Will be above maximum because the vega wallet doesn't have any collateral
|
||||
cy.get(amountField).clear().type('1001', { delay: 100 });
|
||||
cy.getByTestId(submitWithdrawBtn).click();
|
||||
@@ -63,7 +60,6 @@ describe('withdraw form validation', { tags: '@smoke' }, () => {
|
||||
});
|
||||
|
||||
it('can set amount using use maximum button', () => {
|
||||
// 1002-WITH-004
|
||||
selectAsset(ASSET_SEPOLIA_TBTC);
|
||||
cy.getByTestId(useMaximumAmount).click();
|
||||
cy.get(amountField).should('have.value', '1000.00000');
|
||||
@@ -72,9 +68,6 @@ describe('withdraw form validation', { tags: '@smoke' }, () => {
|
||||
|
||||
describe('withdraw actions', { tags: '@regression' }, () => {
|
||||
// this is extremely ugly hack, but setting it properly in contract is too much effort for such simple validation
|
||||
|
||||
// 1002-WITH-018
|
||||
|
||||
const withdrawalThreshold =
|
||||
Cypress.env('VEGA_ENV') === 'CUSTOM' ? '0.00' : '100.00';
|
||||
before(() => {
|
||||
@@ -95,8 +88,6 @@ describe('withdraw actions', { tags: '@regression' }, () => {
|
||||
});
|
||||
|
||||
it('triggers transaction when submitted', () => {
|
||||
// 1002-WITH-002
|
||||
// 1002-WITH-003
|
||||
selectAsset(ASSET_SEPOLIA_TBTC);
|
||||
cy.getByTestId('BALANCE_AVAILABLE_label').should(
|
||||
'contain.text',
|
||||
@@ -117,4 +108,7 @@ describe('withdraw actions', { tags: '@regression' }, () => {
|
||||
cy.getByTestId(submitWithdrawBtn).click();
|
||||
cy.getByTestId('toast').should('contain.text', 'Awaiting confirmation');
|
||||
});
|
||||
|
||||
it.skip('creates a withdrawal on submit'); // Needs capsule
|
||||
it.skip('creates a withdrawal on submit and prompts to complete withdrawal'); // Needs capsule
|
||||
});
|
||||
|
||||
@@ -8,4 +8,3 @@ NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"
|
||||
NX_VEGA_TOKEN_URL=https://token.fairground.wtf
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
|
||||
@@ -9,7 +9,6 @@ NX_VEGA_TOKEN_URL=https://token.fairground.wtf
|
||||
NX_VEGA_URL=http://localhost:3028/query
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
|
||||
NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/
|
||||
NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session"
|
||||
@@ -8,4 +8,3 @@ NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"
|
||||
NX_VEGA_TOKEN_URL=https://token.fairground.wtf
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases
|
||||
|
||||
@@ -7,4 +7,3 @@ NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\",\"TESTNET\":\"h
|
||||
NX_VEGA_TOKEN_URL=https://token.vega.xyz
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
|
||||
@@ -7,5 +7,4 @@ NX_VEGA_EXPLORER_URL=https://mainnet-mirror.explorer.vega.xyz
|
||||
NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://stagnet1.console.vega.xyz\",\"STAGNET3\":\"https://stagnet3.console.vega.xyz\"}
|
||||
NX_VEGA_TOKEN_URL=https://mainnet-mirror.token.vega.xyz
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
@@ -7,4 +7,3 @@ NX_VEGA_NETWORKS={\"DEVNET\":\"https://dev.token.vega.xyz\",\"STAGNET3\":\"https
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/sandbox-network.json
|
||||
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
|
||||
@@ -8,4 +8,3 @@ NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"
|
||||
NX_VEGA_TOKEN_URL=https://stagnet1.token.vega.xyz
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
|
||||
@@ -8,4 +8,3 @@ NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"
|
||||
NX_VEGA_TOKEN_URL=https://token.fairground.wtf
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega-dev-releases/releases
|
||||
|
||||
@@ -8,4 +8,3 @@ NX_VEGA_NETWORKS={\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"
|
||||
NX_VEGA_TOKEN_URL=https://token.fairground.wtf
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
|
||||
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
|
||||
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
|
||||
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/validator-testnet-network.json
|
||||
NX_VEGA_ENV=VALIDATOR_TESTNET
|
||||
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
|
||||
NX_VEGA_TOKEN_URL=https://token.fairground.wtf
|
||||
NX_VEGA_WALLET_URL=http://localhost:1789
|
||||
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
addDecimal,
|
||||
fromISONano,
|
||||
fromNanoSeconds,
|
||||
t,
|
||||
useThemeSwitcher,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
@@ -228,7 +228,7 @@ export const AccountHistoryChart = ({
|
||||
.reduce((acc, edge) => {
|
||||
if (edge.node.accountType === accountType) {
|
||||
acc?.push({
|
||||
datetime: fromISONano(edge.node.timestamp),
|
||||
datetime: fromNanoSeconds(edge.node.timestamp),
|
||||
balance: Number(addDecimal(edge.node.balance, asset.decimals)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { t, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
|
||||
export const DepositsContainer = () => {
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: depositsProvider,
|
||||
variables: { partyId: pubKey || '' },
|
||||
@@ -30,17 +30,15 @@ export const DepositsContainer = () => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{!isReadOnly && (
|
||||
<div className="w-full dark:bg-black bg-white absolute bottom-0 h-auto flex justify-end px-[11px] py-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => openDepositDialog()}
|
||||
data-testid="deposit-button"
|
||||
>
|
||||
{t('Deposit')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full dark:bg-black bg-white absolute bottom-0 h-auto flex justify-end px-[11px] py-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => openDepositDialog()}
|
||||
data-testid="deposit-button"
|
||||
>
|
||||
{t('Deposit')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ import { t, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { VegaWalletContainer } from '../../components/vega-wallet-container';
|
||||
|
||||
export const WithdrawalsContainer = () => {
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: withdrawalProvider,
|
||||
variables: { partyId: pubKey || '' },
|
||||
@@ -36,17 +36,15 @@ export const WithdrawalsContainer = () => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{!isReadOnly && (
|
||||
<div className="w-full dark:bg-black bg-white absolute bottom-0 h-auto flex justify-end px-[11px] py-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => openWithdrawDialog()}
|
||||
data-testid="withdraw-dialog-button"
|
||||
>
|
||||
{t('Make withdrawal')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full dark:bg-black bg-white absolute bottom-0 h-auto flex justify-end px-[11px] py-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => openWithdrawDialog()}
|
||||
data-testid="withdraw-dialog-button"
|
||||
>
|
||||
{t('Make withdrawal')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</VegaWalletContainer>
|
||||
);
|
||||
|
||||
@@ -5,15 +5,14 @@ import { useWithdrawalDialog } from '@vegaprotocol/withdraws';
|
||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { AccountManager, useTransferDialog } from '@vegaprotocol/accounts';
|
||||
import { AccountManager } from '@vegaprotocol/accounts';
|
||||
import { useDepositDialog } from '@vegaprotocol/deposits';
|
||||
|
||||
export const AccountsContainer = () => {
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
const { pubKey } = useVegaWallet();
|
||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||
const openWithdrawalDialog = useWithdrawalDialog((store) => store.open);
|
||||
const openDepositDialog = useDepositDialog((store) => store.open);
|
||||
const openTransferDialog = useTransferDialog((store) => store.open);
|
||||
|
||||
const onClickAsset = useCallback(
|
||||
(assetId?: string) => {
|
||||
@@ -38,19 +37,13 @@ export const AccountsContainer = () => {
|
||||
onClickAsset={onClickAsset}
|
||||
onClickWithdraw={openWithdrawalDialog}
|
||||
onClickDeposit={openDepositDialog}
|
||||
isReadOnly={isReadOnly}
|
||||
/>
|
||||
</div>
|
||||
{!isReadOnly && (
|
||||
<div className="flex gap-2 justify-end p-2 px-[11px]">
|
||||
<Button size="sm" onClick={() => openTransferDialog()}>
|
||||
{t('Transfer')}
|
||||
</Button>
|
||||
<Button size="sm" onClick={() => openDepositDialog()}>
|
||||
{t('Deposit')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex justify-end p-2 px-[11px]">
|
||||
<Button size="sm" onClick={() => openDepositDialog()}>
|
||||
{t('Deposit')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import {
|
||||
AnnouncementBanner,
|
||||
ExternalLink,
|
||||
Icon,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
|
||||
export const Banner = () => {
|
||||
const { update, shouldDisplayAnnouncementBanner } = useGlobalStore(
|
||||
(store) => ({
|
||||
update: store.update,
|
||||
shouldDisplayAnnouncementBanner: store.shouldDisplayAnnouncementBanner,
|
||||
})
|
||||
);
|
||||
|
||||
// Return an empty div so that the grid layout in _app.page.ts
|
||||
// renders correctly
|
||||
if (!shouldDisplayAnnouncementBanner) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
return (
|
||||
<AnnouncementBanner>
|
||||
<div className="grid grid-cols-[auto_1fr] gap-4 font-alpha calt uppercase text-center text-lg text-white">
|
||||
<button
|
||||
onClick={() => update({ shouldDisplayAnnouncementBanner: false })}
|
||||
>
|
||||
<Icon name="cross" className="w-6 h-6" ariaLabel="dismiss" />
|
||||
</button>
|
||||
<div>
|
||||
<span className="pr-4">The Mainnet sims are live!</span>
|
||||
<ExternalLink href="https://fairground.wtf/">
|
||||
Come help stress test the network
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</div>
|
||||
</AnnouncementBanner>
|
||||
);
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export * from './banner';
|
||||
@@ -1,6 +1,6 @@
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { Footer, NodeHealth } from './footer';
|
||||
import { useEnvironment, useNodeHealth } from '@vegaprotocol/environment';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
|
||||
jest.mock('@vegaprotocol/environment');
|
||||
|
||||
@@ -12,14 +12,10 @@ describe('Footer', () => {
|
||||
// @ts-ignore mock env hook
|
||||
useEnvironment.mockImplementation(() => ({
|
||||
VEGA_URL: `https://api.${node}/graphql`,
|
||||
blockDifference: 0,
|
||||
setNodeSwitcherOpen: mockOpenNodeSwitcher,
|
||||
}));
|
||||
|
||||
// @ts-ignore mock env hook
|
||||
useNodeHealth.mockImplementation(() => ({
|
||||
blockDiff: 0,
|
||||
}));
|
||||
|
||||
render(<Footer />);
|
||||
|
||||
fireEvent.click(screen.getByText(node));
|
||||
@@ -33,14 +29,10 @@ describe('Footer', () => {
|
||||
// @ts-ignore mock env hook
|
||||
useEnvironment.mockImplementation(() => ({
|
||||
VEGA_URL: `https://api.${node}/graphql`,
|
||||
blockDifference: 0,
|
||||
setNodeSwitcherOpen: mockOpenNodeSwitcher,
|
||||
}));
|
||||
|
||||
// @ts-ignore mock env hook
|
||||
useNodeHealth.mockImplementation(() => ({
|
||||
blockDiff: 0,
|
||||
}));
|
||||
|
||||
render(<Footer />);
|
||||
|
||||
fireEvent.click(screen.getByText('Operational'));
|
||||
@@ -51,13 +43,13 @@ describe('Footer', () => {
|
||||
describe('NodeHealth', () => {
|
||||
const cases = [
|
||||
{ diff: 0, classname: 'bg-success', text: 'Operational' },
|
||||
{ diff: -1, classname: 'bg-success', text: 'Operational' },
|
||||
{ diff: 5, classname: 'bg-warning', text: '5 Blocks behind' },
|
||||
{ diff: null, classname: 'bg-danger', text: 'Non operational' },
|
||||
{ diff: -1, classname: 'bg-danger', text: 'Non operational' },
|
||||
];
|
||||
it.each(cases)(
|
||||
'renders correct text and indicator color for $diff block difference',
|
||||
(elem) => {
|
||||
console.log(elem);
|
||||
render(<NodeHealth blockDiff={elem.diff} openNodeSwitcher={jest.fn()} />);
|
||||
expect(screen.getByTestId('indicator')).toHaveClass(elem.classname);
|
||||
expect(screen.getByText(elem.text)).toBeInTheDocument();
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { useEnvironment, useNodeHealth } from '@vegaprotocol/environment';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { t, useNavigatorOnline } from '@vegaprotocol/react-helpers';
|
||||
import { ButtonLink, Indicator, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export const Footer = () => {
|
||||
const { VEGA_URL, setNodeSwitcherOpen } = useEnvironment();
|
||||
const { blockDiff } = useNodeHealth();
|
||||
const { VEGA_URL, blockDifference, setNodeSwitcherOpen } = useEnvironment();
|
||||
return (
|
||||
<footer className="px-4 py-1 text-xs border-t border-default">
|
||||
<div className="flex justify-between">
|
||||
@@ -12,9 +11,10 @@ export const Footer = () => {
|
||||
{VEGA_URL && (
|
||||
<>
|
||||
<NodeHealth
|
||||
blockDiff={blockDiff}
|
||||
blockDiff={blockDifference}
|
||||
openNodeSwitcher={setNodeSwitcherOpen}
|
||||
/>
|
||||
{' | '}
|
||||
<NodeUrl url={VEGA_URL} openNodeSwitcher={setNodeSwitcherOpen} />
|
||||
</>
|
||||
)}
|
||||
@@ -37,8 +37,8 @@ const NodeUrl = ({ url, openNodeSwitcher }: NodeUrlProps) => {
|
||||
};
|
||||
|
||||
interface NodeHealthProps {
|
||||
blockDiff: number | null;
|
||||
openNodeSwitcher: () => void;
|
||||
blockDiff: number;
|
||||
}
|
||||
|
||||
// How many blocks behind the most advanced block that is
|
||||
@@ -57,7 +57,7 @@ export const NodeHealth = ({
|
||||
if (!online) {
|
||||
text = t('Offline');
|
||||
intent = Intent.Danger;
|
||||
} else if (blockDiff === null) {
|
||||
} else if (blockDiff < 0) {
|
||||
// Block height query failed and null was returned
|
||||
text = t('Non operational');
|
||||
intent = Intent.Danger;
|
||||
@@ -67,9 +67,9 @@ export const NodeHealth = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<span>
|
||||
<Indicator variant={intent} />
|
||||
<ButtonLink onClick={openNodeSwitcher}>{text}</ButtonLink>
|
||||
</>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ export const Header = ({ title, children }: TradeMarketHeaderProps) => {
|
||||
<div className="px-4 xl:px-0 pb-2 xl:pb-3">{title}</div>
|
||||
<div
|
||||
data-testid="header-summary"
|
||||
className="flex flex-nowrap items-end xl:flex-1 w-full overflow-x-auto text-xs"
|
||||
className="flex flex-nowrap items-start xl:flex-1 w-full overflow-x-auto text-xs"
|
||||
>
|
||||
{Children.map(children, (child, index) => {
|
||||
if (!child) return null;
|
||||
|
||||
@@ -1,25 +1,11 @@
|
||||
import type { RefObject } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { t, useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { TradingModeTooltip } from '@vegaprotocol/deal-ticket';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { useStaticMarketData } from '@vegaprotocol/market-list';
|
||||
import { HeaderStat } from '../header';
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import { marketDataProvider } from '@vegaprotocol/market-list';
|
||||
|
||||
// This will cause often re-rendering
|
||||
// Here it may not be a problem because the component is not very complex
|
||||
// In general, we should avoid using this marketData hook without any throttling
|
||||
const useMarketData = (marketId?: string, skip?: boolean) => {
|
||||
const variables = useMemo(() => ({ marketId }), [marketId]);
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: marketDataProvider,
|
||||
variables,
|
||||
skip: skip || !marketId,
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
const getTradingModeLabel = (
|
||||
tradingMode?: Schema.MarketTradingMode,
|
||||
@@ -49,7 +35,7 @@ export const HeaderStatMarketTradingMode = ({
|
||||
initialTradingMode,
|
||||
initialTrigger,
|
||||
}: HeaderStatMarketTradingModeProps) => {
|
||||
const data = useMarketData(marketId);
|
||||
const data = useStaticMarketData(marketId);
|
||||
const tradingMode = data?.marketTradingMode ?? initialTradingMode;
|
||||
const trigger = data?.trigger ?? initialTrigger;
|
||||
|
||||
@@ -75,7 +61,7 @@ export const MarketTradingMode = ({
|
||||
inViewRoot?: RefObject<Element>;
|
||||
}) => {
|
||||
const [ref, inView] = useInView({ root: inViewRoot?.current });
|
||||
const data = useMarketData(marketId, !inView);
|
||||
const data = useStaticMarketData(marketId, !inView);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
useLinks,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
import { useGlobalStore } from '../../stores/global';
|
||||
import { VegaWalletConnectButton } from '../vega-wallet-connect-button';
|
||||
import {
|
||||
Drawer,
|
||||
@@ -165,7 +165,7 @@ export const Navbar = ({ navbarTheme = 'inherit' }: NavbarProps) => {
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<LinkList className="hidden md:flex md:px-2" navbarTheme={navbarTheme} />
|
||||
<LinkList className="hidden md:flex" navbarTheme={navbarTheme} />
|
||||
<div className="flex items-center gap-2 ml-auto overflow-hidden">
|
||||
<VegaWalletConnectButton />
|
||||
<ThemeSwitcher className="hidden md:block" />
|
||||
|
||||
@@ -151,8 +151,6 @@ const MARKET_B: PartialMarket = {
|
||||
};
|
||||
|
||||
describe('SelectMarket', () => {
|
||||
const table = document.createElement('table');
|
||||
|
||||
it('should render the SelectAllMarketsTableBody', () => {
|
||||
const onSelect = jest.fn();
|
||||
const onCellClick = jest.fn();
|
||||
@@ -164,7 +162,7 @@ describe('SelectMarket', () => {
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</MemoryRouter>,
|
||||
{ wrapper: MockedProvider, container: document.body.appendChild(table) }
|
||||
{ wrapper: MockedProvider }
|
||||
);
|
||||
expect(screen.getByText('ABCDEF')).toBeTruthy(); // name
|
||||
expect(screen.getByText('25.00%')).toBeTruthy(); // price change
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { VegaTransaction } from './vega-transaction';
|
||||
@@ -0,0 +1,57 @@
|
||||
import { WithdrawalFeedback } from '@vegaprotocol/withdraws';
|
||||
import { OrderFeedback } from '@vegaprotocol/orders';
|
||||
|
||||
import {
|
||||
VegaDialog,
|
||||
VegaTxStatus,
|
||||
isWithdrawTransaction,
|
||||
isOrderCancellationTransaction,
|
||||
isOrderSubmissionTransaction,
|
||||
isOrderAmendmentTransaction,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import type { VegaStoredTxState } from '@vegaprotocol/wallet';
|
||||
import { useEthWithdrawApprovalsStore } from '@vegaprotocol/web3';
|
||||
|
||||
export const VegaTransaction = ({
|
||||
transaction,
|
||||
}: {
|
||||
transaction: VegaStoredTxState;
|
||||
}) => {
|
||||
const createEthWithdrawalApproval = useEthWithdrawApprovalsStore(
|
||||
(state) => state.create
|
||||
);
|
||||
if (isWithdrawTransaction(transaction.body)) {
|
||||
if (
|
||||
transaction.status === VegaTxStatus.Complete &&
|
||||
transaction.withdrawal
|
||||
) {
|
||||
return (
|
||||
<WithdrawalFeedback
|
||||
transaction={transaction}
|
||||
withdrawal={transaction.withdrawal}
|
||||
availableTimestamp={null}
|
||||
submitWithdraw={() => {
|
||||
if (!transaction?.withdrawal) {
|
||||
return;
|
||||
}
|
||||
createEthWithdrawalApproval(
|
||||
transaction.withdrawal,
|
||||
transaction.withdrawalApproval
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
} else if (
|
||||
(isOrderCancellationTransaction(transaction.body) ||
|
||||
isOrderSubmissionTransaction(transaction.body) ||
|
||||
isOrderAmendmentTransaction(transaction.body)) &&
|
||||
transaction.status === VegaTxStatus.Complete &&
|
||||
transaction.order
|
||||
) {
|
||||
return (
|
||||
<OrderFeedback transaction={transaction} order={transaction.order} />
|
||||
);
|
||||
}
|
||||
return <VegaDialog transaction={transaction} />;
|
||||
};
|
||||
@@ -13,13 +13,11 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
Icon,
|
||||
Drawer,
|
||||
DropdownMenuSeparator,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { PubKey } from '@vegaprotocol/wallet';
|
||||
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import { WalletIcon } from '../icons/wallet';
|
||||
import { useTransferDialog } from '@vegaprotocol/accounts';
|
||||
|
||||
const MobileWalletButton = ({
|
||||
isConnected,
|
||||
@@ -32,7 +30,6 @@ const MobileWalletButton = ({
|
||||
const openVegaWalletDialog = useVegaWalletDialogStore(
|
||||
(store) => store.openVegaWalletDialog
|
||||
);
|
||||
const openTransferDialog = useTransferDialog((store) => store.open);
|
||||
const { VEGA_ENV } = useEnvironment();
|
||||
const isYellow = VEGA_ENV === Networks.TESTNET;
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
@@ -118,16 +115,7 @@ const MobileWalletButton = ({
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 m-4">
|
||||
<Button
|
||||
onClick={() => {
|
||||
setDrawerOpen(false);
|
||||
openTransferDialog(true);
|
||||
}}
|
||||
fill
|
||||
>
|
||||
{t('Transfer')}
|
||||
</Button>
|
||||
<div className="m-4">
|
||||
<Button onClick={mobileDisconnect} fill>
|
||||
{t('Disconnect')}
|
||||
</Button>
|
||||
@@ -143,7 +131,6 @@ export const VegaWalletConnectButton = () => {
|
||||
const openVegaWalletDialog = useVegaWalletDialogStore(
|
||||
(store) => store.openVegaWalletDialog
|
||||
);
|
||||
const openTransferDialog = useTransferDialog((store) => store.open);
|
||||
const { pubKey, pubKeys, selectPubKey, disconnect } = useVegaWallet();
|
||||
const isConnected = pubKey !== null;
|
||||
|
||||
@@ -184,10 +171,6 @@ export const VegaWalletConnectButton = () => {
|
||||
<KeypairItem key={pk.publicKey} pk={pk} />
|
||||
))}
|
||||
</DropdownMenuRadioGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => openTransferDialog(true)}>
|
||||
{t('Transfer')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem data-testid="disconnect" onClick={disconnect}>
|
||||
{t('Disconnect')}
|
||||
</DropdownMenuItem>
|
||||
|
||||
@@ -3,12 +3,8 @@ import { useAssetsDataProvider } from '@vegaprotocol/assets';
|
||||
import { ETHERSCAN_TX, useEtherscanLink } from '@vegaprotocol/environment';
|
||||
import { formatNumber, t, toBigNum } from '@vegaprotocol/react-helpers';
|
||||
import type { Toast, ToastContent } from '@vegaprotocol/ui-toolkit';
|
||||
import { ToastHeading } from '@vegaprotocol/ui-toolkit';
|
||||
import { Panel } from '@vegaprotocol/ui-toolkit';
|
||||
import { CLOSE_AFTER } from '@vegaprotocol/ui-toolkit';
|
||||
import { useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { ExternalLink, Intent, ProgressBar } from '@vegaprotocol/ui-toolkit';
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import compact from 'lodash/compact';
|
||||
import type { EthStoredTxState } from '@vegaprotocol/web3';
|
||||
import {
|
||||
@@ -48,35 +44,34 @@ const EthTransactionDetails = ({ tx }: { tx: EthStoredTxState }) => {
|
||||
if (isWithdraw) label = t('Withdraw');
|
||||
if (isDeposit) label = t('Deposit');
|
||||
assetInfo = (
|
||||
<strong>
|
||||
{label}{' '}
|
||||
{formatNumber(toBigNum(tx.args[1], asset.decimals), asset.decimals)}{' '}
|
||||
{asset.symbol}
|
||||
</strong>
|
||||
<div className="mt-[5px]">
|
||||
<span className="font-mono text-xs p-1 bg-gray-100 rounded">
|
||||
{label}{' '}
|
||||
{formatNumber(toBigNum(tx.args[1], asset.decimals), asset.decimals)}{' '}
|
||||
{asset.symbol}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (assetInfo || tx.requiresConfirmation) {
|
||||
return (
|
||||
<Panel>
|
||||
{assetInfo}
|
||||
{tx.status === EthTxStatus.Pending && (
|
||||
<>
|
||||
<p className="mt-[2px]">
|
||||
{t('Awaiting confirmations')}{' '}
|
||||
{`(${tx.confirmations}/${tx.requiredConfirmations})`}
|
||||
</p>
|
||||
<ProgressBar
|
||||
value={(tx.confirmations / tx.requiredConfirmations) * 100}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
return (
|
||||
<>
|
||||
{assetInfo}
|
||||
{tx.status === EthTxStatus.Pending && (
|
||||
<div className="mt-[10px]">
|
||||
<span className="font-mono text-xs">
|
||||
{t('Awaiting confirmations')}{' '}
|
||||
{`(${tx.confirmations}/${tx.requiredConfirmations})`}
|
||||
</span>
|
||||
<ProgressBar
|
||||
value={(tx.confirmations / tx.requiredConfirmations) * 100}
|
||||
intent={Intent.Warning}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
type EthTxToastContentProps = {
|
||||
@@ -85,26 +80,26 @@ type EthTxToastContentProps = {
|
||||
|
||||
const EthTxRequestedToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
return (
|
||||
<>
|
||||
<ToastHeading>{t('Action required')}</ToastHeading>
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Action required')}</h3>
|
||||
<p>
|
||||
{t(
|
||||
'Please go to your wallet application and approve or reject the transaction.'
|
||||
)}
|
||||
</p>
|
||||
<EthTransactionDetails tx={tx} />
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const EthTxPendingToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
return (
|
||||
<>
|
||||
<ToastHeading>{t('Awaiting confirmation')}</ToastHeading>
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Awaiting confirmation')}</h3>
|
||||
<p>{t('Please wait for your transaction to be confirmed.')}</p>
|
||||
<EtherscanLink tx={tx} />
|
||||
<EthTransactionDetails tx={tx} />
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -117,11 +112,11 @@ const EthTxErrorToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
errorMessage = tx.error.message;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<ToastHeading>{t('Error occurred')}</ToastHeading>
|
||||
<p className="first-letter:uppercase">{errorMessage}</p>
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Error occurred')}</h3>
|
||||
<p>{errorMessage}</p>
|
||||
<EthTransactionDetails tx={tx} />
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -141,63 +136,42 @@ const EtherscanLink = ({ tx }: EthTxToastContentProps) => {
|
||||
|
||||
const EthTxConfirmedToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
return (
|
||||
<>
|
||||
<ToastHeading>{t('Transaction confirmed')}</ToastHeading>
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Transaction confirmed')}</h3>
|
||||
<p>{t('Your transaction has been confirmed.')}</p>
|
||||
<EtherscanLink tx={tx} />
|
||||
<EthTransactionDetails tx={tx} />
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const EthTxCompletedToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
const isDeposit = isDepositTransaction(tx);
|
||||
return (
|
||||
<>
|
||||
<ToastHeading>
|
||||
<div>
|
||||
<h3 className="font-bold">
|
||||
{t('Processing')} {isDeposit && t('deposit')}
|
||||
</ToastHeading>
|
||||
</h3>
|
||||
<p>
|
||||
{t('Your transaction has been completed.')}{' '}
|
||||
{isDeposit && t('Waiting for deposit confirmation.')}
|
||||
</p>
|
||||
<EtherscanLink tx={tx} />
|
||||
<EthTransactionDetails tx={tx} />
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const isFinal = (tx: EthStoredTxState) =>
|
||||
[EthTxStatus.Confirmed, EthTxStatus.Error].includes(tx.status);
|
||||
|
||||
export const useEthereumTransactionToasts = () => {
|
||||
const [setToast, removeToast] = useToasts((store) => [
|
||||
store.setToast,
|
||||
store.remove,
|
||||
]);
|
||||
|
||||
const [dismissTx, deleteTx] = useEthTransactionStore((state) => [
|
||||
state.dismiss,
|
||||
state.delete,
|
||||
]);
|
||||
|
||||
const onClose = useCallback(
|
||||
(tx: EthStoredTxState) => () => {
|
||||
const safeToDelete = isFinal(tx);
|
||||
if (safeToDelete) {
|
||||
deleteTx(tx.id);
|
||||
} else {
|
||||
dismissTx(tx.id);
|
||||
}
|
||||
removeToast(`eth-${tx.id}`);
|
||||
},
|
||||
[deleteTx, dismissTx, removeToast]
|
||||
const ethTransactions = useEthTransactionStore((state) =>
|
||||
state.transactions.filter((transaction) => transaction?.dialogOpen)
|
||||
);
|
||||
const dismissEthTransaction = useEthTransactionStore(
|
||||
(state) => state.dismiss
|
||||
);
|
||||
|
||||
const fromEthTransaction = useCallback(
|
||||
(tx: EthStoredTxState): Toast => {
|
||||
let content: ToastContent = <TransactionContent {...tx} />;
|
||||
const closeAfter = isFinal(tx) ? CLOSE_AFTER : undefined;
|
||||
if (tx.status === EthTxStatus.Requested) {
|
||||
content = <EthTxRequestedToastContent tx={tx} />;
|
||||
}
|
||||
@@ -217,21 +191,15 @@ export const useEthereumTransactionToasts = () => {
|
||||
return {
|
||||
id: `eth-${tx.id}`,
|
||||
intent: intentMap[tx.status],
|
||||
onClose: onClose(tx),
|
||||
onClose: () => dismissEthTransaction(tx.id),
|
||||
loader: [EthTxStatus.Pending, EthTxStatus.Complete].includes(tx.status),
|
||||
content,
|
||||
closeAfter,
|
||||
};
|
||||
},
|
||||
[onClose]
|
||||
[dismissEthTransaction]
|
||||
);
|
||||
|
||||
useEthTransactionStore.subscribe(
|
||||
(state) => compact(state.transactions.filter((tx) => tx?.dialogOpen)),
|
||||
(txs) => {
|
||||
txs.forEach((tx) => {
|
||||
setToast(fromEthTransaction(tx));
|
||||
});
|
||||
}
|
||||
);
|
||||
return useMemo(() => {
|
||||
return [...compact(ethTransactions).map(fromEthTransaction)];
|
||||
}, [ethTransactions, fromEthTransaction]);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import { formatNumber, t, toBigNum } from '@vegaprotocol/react-helpers';
|
||||
import type { Toast } from '@vegaprotocol/ui-toolkit';
|
||||
import { ToastHeading } from '@vegaprotocol/ui-toolkit';
|
||||
import { Panel } from '@vegaprotocol/ui-toolkit';
|
||||
import { CLOSE_AFTER } from '@vegaprotocol/ui-toolkit';
|
||||
import { useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { ApprovalStatus, VerificationStatus } from '@vegaprotocol/withdraws';
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import compact from 'lodash/compact';
|
||||
import type { EthWithdrawalApprovalState } from '@vegaprotocol/web3';
|
||||
import { useEthWithdrawApprovalsStore } from '@vegaprotocol/web3';
|
||||
@@ -34,72 +30,49 @@ const EthWithdrawalApprovalToastContent = ({
|
||||
if (tx.status === ApprovalStatus.Delayed) {
|
||||
title = t('Delayed');
|
||||
}
|
||||
if (tx.status === ApprovalStatus.Ready) {
|
||||
title = t('Approved');
|
||||
}
|
||||
const num = formatNumber(
|
||||
toBigNum(tx.withdrawal.amount, tx.withdrawal.asset.decimals),
|
||||
tx.withdrawal.asset.decimals
|
||||
);
|
||||
const details = (
|
||||
<Panel>
|
||||
<strong>
|
||||
<div className="mt-[5px]">
|
||||
<span className="font-mono text-xs p-1 bg-gray-100 rounded">
|
||||
{t('Withdraw')} {num} {tx.withdrawal.asset.symbol}
|
||||
</strong>
|
||||
</Panel>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
{title.length > 0 && (
|
||||
<ToastHeading className="font-bold">{title}</ToastHeading>
|
||||
)}
|
||||
<div>
|
||||
{title.length > 0 && <h3 className="font-bold">{title}</h3>}
|
||||
<VerificationStatus state={tx} />
|
||||
{details}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const isFinal = (tx: EthWithdrawalApprovalState) =>
|
||||
[ApprovalStatus.Ready, ApprovalStatus.Error].includes(tx.status);
|
||||
|
||||
export const useEthereumWithdrawApprovalsToasts = () => {
|
||||
const [setToast, remove] = useToasts((state) => [
|
||||
state.setToast,
|
||||
state.remove,
|
||||
]);
|
||||
const [dismissTx, deleteTx] = useEthWithdrawApprovalsStore((state) => [
|
||||
state.dismiss,
|
||||
state.delete,
|
||||
]);
|
||||
const { withdrawApprovals, dismissWithdrawApproval } =
|
||||
useEthWithdrawApprovalsStore((state) => ({
|
||||
withdrawApprovals: state.transactions.filter(
|
||||
(transaction) => transaction?.dialogOpen
|
||||
),
|
||||
dismissWithdrawApproval: state.dismiss,
|
||||
}));
|
||||
|
||||
const fromWithdrawalApproval = useCallback(
|
||||
(tx: EthWithdrawalApprovalState): Toast => ({
|
||||
id: `withdrawal-${tx.id}`,
|
||||
intent: intentMap[tx.status],
|
||||
onClose: () => {
|
||||
if ([ApprovalStatus.Error, ApprovalStatus.Ready].includes(tx.status)) {
|
||||
deleteTx(tx.id);
|
||||
} else {
|
||||
dismissTx(tx.id);
|
||||
}
|
||||
remove(`withdrawal-${tx.id}`);
|
||||
},
|
||||
onClose: () => dismissWithdrawApproval(tx.id),
|
||||
loader: tx.status === ApprovalStatus.Pending,
|
||||
content: <EthWithdrawalApprovalToastContent tx={tx} />,
|
||||
closeAfter: isFinal(tx) ? CLOSE_AFTER : undefined,
|
||||
}),
|
||||
[deleteTx, dismissTx, remove]
|
||||
[dismissWithdrawApproval]
|
||||
);
|
||||
|
||||
useEthWithdrawApprovalsStore.subscribe(
|
||||
(state) =>
|
||||
compact(
|
||||
state.transactions.filter((transaction) => transaction?.dialogOpen)
|
||||
),
|
||||
(txs) => {
|
||||
txs.forEach((tx) => {
|
||||
setToast(fromWithdrawalApproval(tx));
|
||||
});
|
||||
}
|
||||
);
|
||||
const toasts = useMemo(() => {
|
||||
return [...compact(withdrawApprovals).map(fromWithdrawalApproval)];
|
||||
}, [fromWithdrawalApproval, withdrawApprovals]);
|
||||
|
||||
return toasts;
|
||||
};
|
||||
|
||||
@@ -134,7 +134,23 @@ const submitOrder: VegaStoredTxState = {
|
||||
type: OrderType.TYPE_MARKET,
|
||||
price: '1234',
|
||||
createdAt: new Date(),
|
||||
marketId: 'market-1',
|
||||
market: {
|
||||
id: 'market-1',
|
||||
decimalPlaces: 2,
|
||||
positionDecimalPlaces: 2,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
code: 'M1',
|
||||
name: 'M1',
|
||||
product: {
|
||||
settlementAsset: {
|
||||
decimals: 2,
|
||||
symbol: '$A',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
status: OrderStatus.STATUS_ACTIVE,
|
||||
},
|
||||
};
|
||||
@@ -165,7 +181,23 @@ const editOrder: VegaStoredTxState = {
|
||||
type: OrderType.TYPE_MARKET,
|
||||
price: '1234',
|
||||
createdAt: new Date(),
|
||||
marketId: 'market-1',
|
||||
market: {
|
||||
id: 'market-1',
|
||||
decimalPlaces: 2,
|
||||
positionDecimalPlaces: 2,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
code: 'M1',
|
||||
name: 'M1',
|
||||
product: {
|
||||
settlementAsset: {
|
||||
decimals: 2,
|
||||
symbol: '$A',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
status: OrderStatus.STATUS_ACTIVE,
|
||||
},
|
||||
};
|
||||
@@ -260,7 +292,7 @@ describe('VegaTransactionDetails', () => {
|
||||
const { queryByTestId } = render(
|
||||
<VegaTransactionDetails tx={unsupportedTransaction} />
|
||||
);
|
||||
expect(queryByTestId('toast-panel')).toBeNull();
|
||||
expect(queryByTestId('vega-tx-details')).toBeNull();
|
||||
});
|
||||
it.each([
|
||||
{ tx: withdraw, details: 'Withdraw 12.34 $A' },
|
||||
@@ -275,6 +307,6 @@ describe('VegaTransactionDetails', () => {
|
||||
{ tx: batch, details: 'Batch market instruction' },
|
||||
])('display details for transaction', ({ tx, details }) => {
|
||||
const { queryByTestId } = render(<VegaTransactionDetails tx={tx} />);
|
||||
expect(queryByTestId('toast-panel')?.textContent).toEqual(details);
|
||||
expect(queryByTestId('vega-tx-details')?.textContent).toEqual(details);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import { useCallback } from 'react';
|
||||
import first from 'lodash/first';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import compact from 'lodash/compact';
|
||||
import type {
|
||||
BatchMarketInstructionSubmissionBody,
|
||||
OrderAmendment,
|
||||
OrderTxUpdateFieldsFragment,
|
||||
OrderBusEventFieldsFragment,
|
||||
OrderCancellationBody,
|
||||
OrderSubmission,
|
||||
VegaStoredTxState,
|
||||
WithdrawalBusEventFieldsFragment,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import { isBatchMarketInstructionsTransaction } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
isTransferTransaction,
|
||||
isBatchMarketInstructionsTransaction,
|
||||
ClientErrors,
|
||||
useReconnectVegaWallet,
|
||||
WalletError,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import {
|
||||
isOrderAmendmentTransaction,
|
||||
isOrderCancellationTransaction,
|
||||
isOrderSubmissionTransaction,
|
||||
@@ -24,10 +25,6 @@ import {
|
||||
VegaTxStatus,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import type { Toast, ToastContent } from '@vegaprotocol/ui-toolkit';
|
||||
import { ToastHeading } from '@vegaprotocol/ui-toolkit';
|
||||
import { Panel } from '@vegaprotocol/ui-toolkit';
|
||||
import { CLOSE_AFTER } from '@vegaprotocol/ui-toolkit';
|
||||
import { useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { Button, ExternalLink, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
@@ -35,15 +32,14 @@ import {
|
||||
Size,
|
||||
t,
|
||||
toBigNum,
|
||||
truncateByChars,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { useAssetsDataProvider } from '@vegaprotocol/assets';
|
||||
import { useEthWithdrawApprovalsStore } from '@vegaprotocol/web3';
|
||||
import { DApp, EXPLORER_TX, useLinks } from '@vegaprotocol/environment';
|
||||
import { getRejectionReason, useOrderByIdQuery } from '@vegaprotocol/orders';
|
||||
import { useMarketList } from '@vegaprotocol/market-list';
|
||||
import first from 'lodash/first';
|
||||
import type { Side } from '@vegaprotocol/types';
|
||||
import { OrderStatus } from '@vegaprotocol/types';
|
||||
import { OrderStatusMapping } from '@vegaprotocol/types';
|
||||
|
||||
const intentMap: { [s in VegaTxStatus]: Intent } = {
|
||||
@@ -82,17 +78,29 @@ const isTransactionTypeSupported = (tx: VegaStoredTxState) => {
|
||||
const cancelOrder = isOrderCancellationTransaction(tx.body);
|
||||
const editOrder = isOrderAmendmentTransaction(tx.body);
|
||||
const batchMarketInstructions = isBatchMarketInstructionsTransaction(tx.body);
|
||||
const transfer = isTransferTransaction(tx.body);
|
||||
return (
|
||||
withdraw ||
|
||||
submitOrder ||
|
||||
cancelOrder ||
|
||||
editOrder ||
|
||||
batchMarketInstructions ||
|
||||
transfer
|
||||
batchMarketInstructions
|
||||
);
|
||||
};
|
||||
|
||||
const Details = ({
|
||||
children,
|
||||
title = '',
|
||||
}: {
|
||||
children: ReactNode;
|
||||
title?: string;
|
||||
}) => (
|
||||
<div className="pt-[5px]" data-testid="vega-tx-details" title={title}>
|
||||
<div className="font-mono text-xs p-2 bg-neutral-100 rounded dark:bg-neutral-700 dark:text-white">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
type SizeAtPriceProps = {
|
||||
side: Side;
|
||||
size: string;
|
||||
@@ -122,10 +130,12 @@ const SubmitOrderDetails = ({
|
||||
order,
|
||||
}: {
|
||||
data: OrderSubmission;
|
||||
order?: OrderTxUpdateFieldsFragment;
|
||||
order?: OrderBusEventFieldsFragment;
|
||||
}) => {
|
||||
const { data: markets } = useMarketList();
|
||||
const market = markets?.find((m) => m.id === order?.marketId);
|
||||
const market = order
|
||||
? order.market
|
||||
: markets?.find((m) => m.id === data.marketId);
|
||||
if (!market) return null;
|
||||
|
||||
const price = order ? order.price : data.price;
|
||||
@@ -133,8 +143,8 @@ const SubmitOrderDetails = ({
|
||||
const side = order ? order.side : data.side;
|
||||
|
||||
return (
|
||||
<Panel>
|
||||
<h4>
|
||||
<Details>
|
||||
<h4 className="font-bold">
|
||||
{order
|
||||
? t(
|
||||
`Submit order - ${OrderStatusMapping[order.status].toLowerCase()}`
|
||||
@@ -156,7 +166,10 @@ const SubmitOrderDetails = ({
|
||||
price={price}
|
||||
/>
|
||||
</p>
|
||||
</Panel>
|
||||
{order && order.rejectionReason && (
|
||||
<p className="italic">{getRejectionReason(order)}</p>
|
||||
)}
|
||||
</Details>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -165,17 +178,16 @@ const EditOrderDetails = ({
|
||||
order,
|
||||
}: {
|
||||
data: OrderAmendment;
|
||||
order?: OrderTxUpdateFieldsFragment;
|
||||
order?: OrderBusEventFieldsFragment;
|
||||
}) => {
|
||||
const { data: orderById } = useOrderByIdQuery({
|
||||
variables: { orderId: data.orderId },
|
||||
});
|
||||
const { data: markets } = useMarketList();
|
||||
|
||||
const originalOrder = order || orderById?.orderByID;
|
||||
const marketId = order?.marketId || orderById?.orderByID.market.id;
|
||||
const originalOrder = orderById?.orderByID;
|
||||
if (!originalOrder) return null;
|
||||
const market = markets?.find((m) => m.id === marketId);
|
||||
const market = markets?.find((m) => m.id === originalOrder.market.id);
|
||||
if (!market) return null;
|
||||
|
||||
const original = (
|
||||
@@ -207,8 +219,8 @@ const EditOrderDetails = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<Panel title={data.orderId}>
|
||||
<h4>
|
||||
<Details title={data.orderId}>
|
||||
<h4 className="font-bold">
|
||||
{order
|
||||
? t(`Edit order - ${OrderStatusMapping[order.status].toLowerCase()}`)
|
||||
: t('Edit order')}
|
||||
@@ -218,7 +230,10 @@ const EditOrderDetails = ({
|
||||
<s>{original}</s>
|
||||
</p>
|
||||
<p>{edited}</p>
|
||||
</Panel>
|
||||
{order && order.rejectionReason && (
|
||||
<p className="italic">{getRejectionReason(order)}</p>
|
||||
)}
|
||||
</Details>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -227,7 +242,7 @@ const CancelOrderDetails = ({
|
||||
order,
|
||||
}: {
|
||||
orderId: string;
|
||||
order?: OrderTxUpdateFieldsFragment;
|
||||
order?: OrderBusEventFieldsFragment;
|
||||
}) => {
|
||||
const { data: orderById } = useOrderByIdQuery({
|
||||
variables: { orderId },
|
||||
@@ -253,8 +268,8 @@ const CancelOrderDetails = ({
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<Panel title={orderId}>
|
||||
<h4>
|
||||
<Details title={orderId}>
|
||||
<h4 className="font-bold">
|
||||
{order
|
||||
? t(
|
||||
`Cancel order - ${OrderStatusMapping[order.status].toLowerCase()}`
|
||||
@@ -265,7 +280,10 @@ const CancelOrderDetails = ({
|
||||
<p>
|
||||
<s>{original}</s>
|
||||
</p>
|
||||
</Panel>
|
||||
{order && order.rejectionReason && (
|
||||
<p className="italic">{getRejectionReason(order)}</p>
|
||||
)}
|
||||
</Details>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -284,11 +302,9 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
|
||||
asset.decimals
|
||||
);
|
||||
return (
|
||||
<Panel>
|
||||
<strong>
|
||||
{t('Withdraw')} {num} {asset.symbol}
|
||||
</strong>
|
||||
</Panel>
|
||||
<Details>
|
||||
{t('Withdraw')} {num} {asset.symbol}
|
||||
</Details>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -305,7 +321,7 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
|
||||
tx.body.orderCancellation.marketId === undefined &&
|
||||
tx.body.orderCancellation.orderId === undefined
|
||||
) {
|
||||
return <Panel>{t('Cancel all orders')}</Panel>;
|
||||
return <Details>{t('Cancel all orders')}</Details>;
|
||||
}
|
||||
|
||||
// CANCEL
|
||||
@@ -328,15 +344,11 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
|
||||
m.id === (tx.body as OrderCancellationBody).orderCancellation.marketId
|
||||
)?.tradableInstrument.instrument.code;
|
||||
return (
|
||||
<Panel>
|
||||
{marketName ? (
|
||||
<>
|
||||
{t('Cancel all orders for')} <strong>{marketName}</strong>
|
||||
</>
|
||||
) : (
|
||||
t('Cancel all orders')
|
||||
)}
|
||||
</Panel>
|
||||
<Details>
|
||||
{marketName
|
||||
? `${t('Cancel all orders for')} ${marketName}`
|
||||
: t('Cancel all orders')}
|
||||
</Details>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -358,36 +370,15 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
|
||||
const market = marketId && markets?.find((m) => m.id === marketId);
|
||||
if (market) {
|
||||
return (
|
||||
<Panel>
|
||||
{t('Close position for')}{' '}
|
||||
<strong>{market.tradableInstrument.instrument.code}</strong>
|
||||
</Panel>
|
||||
<Details>
|
||||
{t('Close position for')} {market.tradableInstrument.instrument.code}
|
||||
</Details>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isBatchMarketInstructionsTransaction(tx.body)) {
|
||||
return <Panel>{t('Batch market instruction')}</Panel>;
|
||||
}
|
||||
|
||||
if (isTransferTransaction(tx.body)) {
|
||||
const { amount, to, asset } = tx.body.transfer;
|
||||
const transferAsset = assets?.find((a) => a.id === asset);
|
||||
// only render if we have an asset to avoid unformatted amounts showing
|
||||
if (transferAsset) {
|
||||
const value = addDecimalsFormatNumber(amount, transferAsset.decimals);
|
||||
return (
|
||||
<Panel>
|
||||
<h4>{t('Transfer')}</h4>
|
||||
<p>
|
||||
{t('To')} {truncateByChars(to)}
|
||||
</p>
|
||||
<p>
|
||||
{value} {transferAsset.symbol}
|
||||
</p>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
return <Details>{t('Batch market instruction')}</Details>;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -396,22 +387,22 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
|
||||
type VegaTxToastContentProps = { tx: VegaStoredTxState };
|
||||
|
||||
const VegaTxRequestedToastContent = ({ tx }: VegaTxToastContentProps) => (
|
||||
<>
|
||||
<ToastHeading>{t('Action required')}</ToastHeading>
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Action required')}</h3>
|
||||
<p>
|
||||
{t(
|
||||
'Please go to your Vega wallet application and approve or reject the transaction.'
|
||||
)}
|
||||
</p>
|
||||
<VegaTransactionDetails tx={tx} />
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
|
||||
const VegaTxPendingToastContentProps = ({ tx }: VegaTxToastContentProps) => {
|
||||
const explorerLink = useLinks(DApp.Explorer);
|
||||
return (
|
||||
<>
|
||||
<ToastHeading>{t('Awaiting confirmation')}</ToastHeading>
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Awaiting confirmation')}</h3>
|
||||
<p>{t('Please wait for your transaction to be confirmed')}</p>
|
||||
{tx.txHash && (
|
||||
<p className="break-all">
|
||||
@@ -424,7 +415,7 @@ const VegaTxPendingToastContentProps = ({ tx }: VegaTxToastContentProps) => {
|
||||
</p>
|
||||
)}
|
||||
<VegaTransactionDetails tx={tx} />
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -435,10 +426,9 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
})
|
||||
);
|
||||
const explorerLink = useLinks(DApp.Explorer);
|
||||
|
||||
if (isWithdrawTransaction(tx.body)) {
|
||||
const completeWithdrawalButton = tx.withdrawal && (
|
||||
<p className="mt-1">
|
||||
<div className="mt-[10px]">
|
||||
<Button
|
||||
data-testid="toast-complete-withdrawal"
|
||||
size="xs"
|
||||
@@ -451,11 +441,11 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
>
|
||||
{t('Complete withdrawal')}
|
||||
</Button>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<ToastHeading>{t('Funds unlocked')}</ToastHeading>
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Funds unlocked')}</h3>
|
||||
<p>{t('Your funds have been unlocked for withdrawal')}</p>
|
||||
{tx.txHash && (
|
||||
<p className="break-all">
|
||||
@@ -469,68 +459,13 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
)}
|
||||
<VegaTransactionDetails tx={tx} />
|
||||
{completeWithdrawalButton}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (tx.order && tx.order.rejectionReason) {
|
||||
return (
|
||||
<>
|
||||
<ToastHeading>{t('Order rejected')}</ToastHeading>
|
||||
<p>
|
||||
{t(
|
||||
'Your order has been rejected because: %s',
|
||||
getRejectionReason(tx.order) || ''
|
||||
)}
|
||||
</p>
|
||||
{tx.txHash && (
|
||||
<p className="break-all">
|
||||
<ExternalLink
|
||||
href={explorerLink(EXPLORER_TX.replace(':hash', tx.txHash))}
|
||||
rel="noreferrer"
|
||||
>
|
||||
{t('View in block explorer')}
|
||||
</ExternalLink>
|
||||
</p>
|
||||
)}
|
||||
<VegaTransactionDetails tx={tx} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (isOrderSubmissionTransaction(tx.body) && tx.order?.rejectionReason) {
|
||||
return (
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Order rejected')}</h3>
|
||||
<p>{t('Your order was rejected.')}</p>
|
||||
{tx.txHash && (
|
||||
<p className="break-all">
|
||||
<ExternalLink
|
||||
href={explorerLink(EXPLORER_TX.replace(':hash', tx.txHash))}
|
||||
rel="noreferrer"
|
||||
>
|
||||
{t('View in block explorer')}
|
||||
</ExternalLink>
|
||||
</p>
|
||||
)}
|
||||
<VegaTransactionDetails tx={tx} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isTransferTransaction(tx.body)) {
|
||||
return (
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Transfer complete')}</h3>
|
||||
<p>{t('Your transaction has been confirmed ')}</p>
|
||||
<VegaTransactionDetails tx={tx} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ToastHeading>{t('Confirmed')}</ToastHeading>
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Confirmed')}</h3>
|
||||
<p>{t('Your transaction has been confirmed ')}</p>
|
||||
{tx.txHash && (
|
||||
<p className="break-all">
|
||||
@@ -543,7 +478,7 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
</p>
|
||||
)}
|
||||
<VegaTransactionDetails tx={tx} />
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -566,10 +501,7 @@ const VegaTxErrorToastContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
walletNoConnectionCodes.includes(tx.error.code);
|
||||
if (orderRejection) {
|
||||
label = t('Order rejected');
|
||||
errorMessage = t(
|
||||
'Your order has been rejected because: %s',
|
||||
orderRejection
|
||||
);
|
||||
errorMessage = orderRejection;
|
||||
}
|
||||
if (walletError) {
|
||||
label = t('Wallet disconnected');
|
||||
@@ -577,87 +509,60 @@ const VegaTxErrorToastContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ToastHeading>{label}</ToastHeading>
|
||||
<p className="first-letter:uppercase">{errorMessage}</p>
|
||||
<div>
|
||||
<h3 className="font-bold">{label}</h3>
|
||||
<p>{errorMessage}</p>
|
||||
{walletError && (
|
||||
<Button size="xs" onClick={reconnectVegaWallet}>
|
||||
{t('Connect vega wallet')}
|
||||
</Button>
|
||||
)}
|
||||
<VegaTransactionDetails tx={tx} />
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const isFinal = (tx: VegaStoredTxState) =>
|
||||
[VegaTxStatus.Error, VegaTxStatus.Complete].includes(tx.status);
|
||||
|
||||
export const useVegaTransactionToasts = () => {
|
||||
const [setToast, removeToast] = useToasts((store) => [
|
||||
store.setToast,
|
||||
store.remove,
|
||||
]);
|
||||
const vegaTransactions = useVegaTransactionStore((state) =>
|
||||
state.transactions.filter((transaction) => transaction?.dialogOpen)
|
||||
);
|
||||
const dismissVegaTransaction = useVegaTransactionStore(
|
||||
(state) => state.dismiss
|
||||
);
|
||||
|
||||
const [dismissTx, deleteTx] = useVegaTransactionStore((state) => [
|
||||
state.dismiss,
|
||||
state.delete,
|
||||
]);
|
||||
|
||||
const onClose = useCallback(
|
||||
(tx: VegaStoredTxState) => () => {
|
||||
const safeToDelete = isFinal(tx);
|
||||
if (safeToDelete) {
|
||||
deleteTx(tx.id);
|
||||
} else {
|
||||
dismissTx(tx.id);
|
||||
const fromVegaTransaction = useCallback(
|
||||
(tx: VegaStoredTxState): Toast => {
|
||||
let content: ToastContent;
|
||||
if (tx.status === VegaTxStatus.Requested) {
|
||||
content = <VegaTxRequestedToastContent tx={tx} />;
|
||||
}
|
||||
removeToast(`vega-${tx.id}`);
|
||||
if (tx.status === VegaTxStatus.Pending) {
|
||||
content = <VegaTxPendingToastContentProps tx={tx} />;
|
||||
}
|
||||
if (tx.status === VegaTxStatus.Complete) {
|
||||
content = <VegaTxCompleteToastsContent tx={tx} />;
|
||||
}
|
||||
if (tx.status === VegaTxStatus.Error) {
|
||||
content = <VegaTxErrorToastContent tx={tx} />;
|
||||
}
|
||||
return {
|
||||
id: `vega-${tx.id}`,
|
||||
intent: intentMap[tx.status],
|
||||
onClose: () => dismissVegaTransaction(tx.id),
|
||||
loader: tx.status === VegaTxStatus.Pending,
|
||||
content,
|
||||
};
|
||||
},
|
||||
[deleteTx, dismissTx, removeToast]
|
||||
[dismissVegaTransaction]
|
||||
);
|
||||
|
||||
const fromVegaTransaction = (tx: VegaStoredTxState): Toast => {
|
||||
let content: ToastContent;
|
||||
const closeAfter = isFinal(tx) ? CLOSE_AFTER : undefined;
|
||||
if (tx.status === VegaTxStatus.Requested) {
|
||||
content = <VegaTxRequestedToastContent tx={tx} />;
|
||||
}
|
||||
if (tx.status === VegaTxStatus.Pending) {
|
||||
content = <VegaTxPendingToastContentProps tx={tx} />;
|
||||
}
|
||||
if (tx.status === VegaTxStatus.Complete) {
|
||||
content = <VegaTxCompleteToastsContent tx={tx} />;
|
||||
}
|
||||
if (tx.status === VegaTxStatus.Error) {
|
||||
content = <VegaTxErrorToastContent tx={tx} />;
|
||||
}
|
||||
const toasts = useMemo(() => {
|
||||
return [
|
||||
...compact(vegaTransactions)
|
||||
.filter((tx) => isTransactionTypeSupported(tx))
|
||||
.map(fromVegaTransaction),
|
||||
];
|
||||
}, [fromVegaTransaction, vegaTransactions]);
|
||||
|
||||
// Transaction can be successful but the order can be rejected by the network
|
||||
const intent =
|
||||
tx.order && [OrderStatus.STATUS_REJECTED].includes(tx.order.status)
|
||||
? Intent.Danger
|
||||
: intentMap[tx.status];
|
||||
|
||||
return {
|
||||
id: `vega-${tx.id}`,
|
||||
intent,
|
||||
onClose: onClose(tx),
|
||||
loader: tx.status === VegaTxStatus.Pending,
|
||||
content,
|
||||
closeAfter,
|
||||
};
|
||||
};
|
||||
|
||||
useVegaTransactionStore.subscribe(
|
||||
(state) =>
|
||||
compact(
|
||||
state.transactions.filter(
|
||||
(tx) => tx?.dialogOpen && isTransactionTypeSupported(tx)
|
||||
)
|
||||
),
|
||||
(txs) => {
|
||||
txs.forEach((tx) => setToast(fromVegaTransaction(tx)));
|
||||
}
|
||||
);
|
||||
return toasts;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user