Compare commits
44
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88992fa6e6 | ||
|
|
abe650cf95 | ||
|
|
2298c434c8 | ||
|
|
41126111a5 | ||
|
|
f4b11e83df | ||
|
|
0e77062cc6 | ||
|
|
1391db5eed | ||
|
|
717b470a9e | ||
|
|
4df59b9c64 | ||
|
|
23bc8335cc | ||
|
|
8bcdaf4cda | ||
|
|
3eb1359504 | ||
|
|
39cf8ad4d6 | ||
|
|
faef98f0ae | ||
|
|
710e2daa27 | ||
|
|
06ea3924fa | ||
|
|
965e2d8972 | ||
|
|
73de2fed43 | ||
|
|
536859e067 | ||
|
|
54bfaef473 | ||
|
|
e2cad707a7 | ||
|
|
ec8d9798ab | ||
|
|
e629c1e81a | ||
|
|
25feed793c | ||
|
|
2867367e16 | ||
|
|
50b408e74d | ||
|
|
8f531c7c05 | ||
|
|
350d16fee1 | ||
|
|
c052c66266 | ||
|
|
e2032df236 | ||
|
|
9ece19869d | ||
|
|
22abc8160c | ||
|
|
b1a7a22bf9 | ||
|
|
c4b38cc0dc | ||
|
|
44d6d931d5 | ||
|
|
7f1e47d7fd | ||
|
|
0eddfa4073 | ||
|
|
83a034ce91 | ||
|
|
5ab5aa01a2 | ||
|
|
b22f9156b5 | ||
|
|
bab5e2018b | ||
|
|
3f7692ce75 | ||
|
|
b69fb3b0e5 | ||
|
|
83af6e74f6 |
@@ -6,3 +6,4 @@ 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/
|
||||
|
||||
@@ -117,7 +117,7 @@ const NestedDataListItem = ({
|
||||
)}
|
||||
</h4>
|
||||
{!hasChildren && (
|
||||
<code className="text-vega-light-400 mb-2 last:mb-0 dark:text-vega-dark-400 break-all">
|
||||
<code className="text-vega-light-100 mb-2 last:mb-0 dark:text-vega-dark-100 break-all">
|
||||
{JSON.stringify(value, null, ' ')}
|
||||
</code>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import React from 'react';
|
||||
import { StatusMessage } from '../status-message';
|
||||
|
||||
interface RenderFetchedProps {
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
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,6 +19,7 @@ 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';
|
||||
|
||||
interface TxDetailsWrapperProps {
|
||||
txData: BlockExplorerTransactionResult | undefined;
|
||||
@@ -70,6 +71,8 @@ function getTransactionComponent(txData?: BlockExplorerTransactionResult) {
|
||||
return TxDetailsOrder;
|
||||
case 'Submit Oracle Data':
|
||||
return TxDetailsDataSubmission;
|
||||
case 'Protocol Upgrade':
|
||||
return TxDetailsProtocolUpgrade;
|
||||
case 'Cancel Order':
|
||||
return TxDetailsOrderCancel;
|
||||
case 'Amend Order':
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
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'];
|
||||
|
||||
@@ -10,6 +10,7 @@ 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'),
|
||||
@@ -17,6 +18,7 @@ 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')),
|
||||
|
||||
@@ -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> } } } } }, 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 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 ExplorerOracleSpecByIdQueryVariables = Types.Exact<{
|
||||
id: Types.Scalars['ID'];
|
||||
@@ -73,7 +73,7 @@ export const ExplorerOracleDataSourceFragmentDoc = gql`
|
||||
`;
|
||||
export const ExplorerOracleDataConnectionFragmentDoc = gql`
|
||||
fragment ExplorerOracleDataConnection on OracleSpec {
|
||||
dataConnection(pagination: {first: 1}) {
|
||||
dataConnection {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
}
|
||||
@@ -113,13 +113,11 @@ export const ExplorerOracleSpecsDocument = gql`
|
||||
edges {
|
||||
node {
|
||||
...ExplorerOracleDataSource
|
||||
...ExplorerOracleDataConnection
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${ExplorerOracleDataSourceFragmentDoc}
|
||||
${ExplorerOracleDataConnectionFragmentDoc}`;
|
||||
${ExplorerOracleDataSourceFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __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,7 +41,8 @@ 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>
|
||||
@@ -63,7 +64,9 @@ export const OracleDetails = ({
|
||||
</TableRow>
|
||||
</TableWithTbody>
|
||||
<OracleFilter data={dataSource} />
|
||||
{showBroadcasts ? <OracleData data={dataConnection} /> : null}
|
||||
{showBroadcasts && dataConnection ? (
|
||||
<OracleData data={dataConnection} />
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -28,7 +28,7 @@ const Oracles = () => {
|
||||
<OracleDetails
|
||||
id={id}
|
||||
dataSource={o?.node}
|
||||
dataConnection={o?.node}
|
||||
showBroadcasts={false}
|
||||
/>
|
||||
<details>
|
||||
<summary className="pointer">JSON</summary>
|
||||
|
||||
@@ -38,7 +38,7 @@ const Tx = () => {
|
||||
to={`/${Routes.TX}`}
|
||||
>
|
||||
<Icon
|
||||
className="text-vega-light-300 dark:text-vega-light-300"
|
||||
className="text-vega-light-150 dark:text-vega-light-150"
|
||||
name={IconNames.CHEVRON_LEFT}
|
||||
/>
|
||||
All Transactions
|
||||
|
||||
@@ -65,13 +65,46 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tranche_id": 52,
|
||||
"tranche_start": "2024-02-01T00:00:00.000Z",
|
||||
"tranche_end": "2024-08-01T00:00:00.000Z",
|
||||
"total_added": "7500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "7500",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
"user": "0xA530ac2B576eF27C09B7b55C83b3E163D167e9AE",
|
||||
"tx": "0x713ef0adf9a54def857e76c39b10651c5b466296953126cc4661338ea42793fd"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"users": [
|
||||
{
|
||||
"address": "0xA530ac2B576eF27C09B7b55C83b3E163D167e9AE",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
"user": "0xA530ac2B576eF27C09B7b55C83b3E163D167e9AE",
|
||||
"tranche_id": 52,
|
||||
"tx": "0x713ef0adf9a54def857e76c39b10651c5b466296953126cc4661338ea42793fd"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "7500",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "7500"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tranche_id": 49,
|
||||
"tranche_start": "2022-12-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "86666.297",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "72537.154027859368347703",
|
||||
"locked_amount": "71527.9874377224479678513",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "86666.297",
|
||||
@@ -137,7 +170,7 @@
|
||||
"tranche_end": "2023-06-01T00:00:00.000Z",
|
||||
"total_added": "2500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1627.66919134106625",
|
||||
"locked_amount": "1569.28784467846975",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
@@ -331,14 +364,24 @@
|
||||
"tranche_id": 42,
|
||||
"tranche_start": "2023-07-01T00:00:00.000Z",
|
||||
"tranche_end": "2024-01-01T00:00:00.000Z",
|
||||
"total_added": "2500",
|
||||
"total_added": "17500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "2500",
|
||||
"locked_amount": "17500",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
"user": "0x6ad69157EfB1E17EBf6614D352D098589EaE3060",
|
||||
"tx": "0x0e229459260c2e74579e12e05ffd21cb4e470e3a4eacf85b7f924778b4f1c8a6"
|
||||
},
|
||||
{
|
||||
"amount": "7500",
|
||||
"user": "0xd481bCC42265089abEA41Efdb655EDCF8fF9068c",
|
||||
"tx": "0x713ef0adf9a54def857e76c39b10651c5b466296953126cc4661338ea42793fd"
|
||||
},
|
||||
{
|
||||
"amount": "7500",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x713ef0adf9a54def857e76c39b10651c5b466296953126cc4661338ea42793fd"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
@@ -357,6 +400,36 @@
|
||||
"total_tokens": "2500",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "2500"
|
||||
},
|
||||
{
|
||||
"address": "0xd481bCC42265089abEA41Efdb655EDCF8fF9068c",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
"user": "0xd481bCC42265089abEA41Efdb655EDCF8fF9068c",
|
||||
"tranche_id": 42,
|
||||
"tx": "0x713ef0adf9a54def857e76c39b10651c5b466296953126cc4661338ea42793fd"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "7500",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "7500"
|
||||
},
|
||||
{
|
||||
"address": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 42,
|
||||
"tx": "0x713ef0adf9a54def857e76c39b10651c5b466296953126cc4661338ea42793fd"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "7500",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "7500"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -484,8 +557,8 @@
|
||||
"tranche_start": "2023-02-01T00:00:00.000Z",
|
||||
"tranche_end": "2023-08-01T00:00:00.000Z",
|
||||
"total_added": "37500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "37188.0491290669125",
|
||||
"total_removed": "183.137181525",
|
||||
"locked_amount": "36307.49069597912625",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -498,7 +571,13 @@
|
||||
"tx": "0x302591debd812f93121a17dd0413ae5084f3743a868b4325f81990eac58f8292"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "183.137181525",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x326ded5446d14472f79d487ece43dd7db760fec5df52e310342930db38fb5de1"
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"address": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -510,10 +589,17 @@
|
||||
"tx": "0x1a8578ff6c2531d666b92690b7fc02e0512588dae82a44a163f25010224b6272"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "183.137181525",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 34,
|
||||
"tx": "0x326ded5446d14472f79d487ece43dd7db760fec5df52e310342930db38fb5de1"
|
||||
}
|
||||
],
|
||||
"total_tokens": "7500",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "7500"
|
||||
"withdrawn_tokens": "183.137181525",
|
||||
"remaining_tokens": "7316.862818475"
|
||||
},
|
||||
{
|
||||
"address": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
|
||||
@@ -538,7 +624,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "129999.45",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "72470.97300178364112351",
|
||||
"locked_amount": "71462.72714918200044174",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129999.45",
|
||||
@@ -604,7 +690,7 @@
|
||||
"tranche_end": "2023-09-03T00:00:00.000Z",
|
||||
"total_added": "62600",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "36444.23082825976788",
|
||||
"locked_amount": "35715.29892820902776",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10000",
|
||||
@@ -797,7 +883,7 @@
|
||||
"tranche_end": "2023-09-17T00:00:00.000Z",
|
||||
"total_added": "5000",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "3102.661878488077",
|
||||
"locked_amount": "3044.440480720446",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "5000",
|
||||
@@ -1008,7 +1094,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "97499.58",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "14309.4751611591714224046",
|
||||
"locked_amount": "13320.4799021065353983616",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "97499.58",
|
||||
@@ -1041,7 +1127,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "135173.4239508",
|
||||
"total_removed": "98230.390980249184455396",
|
||||
"locked_amount": "19558.58211747851579304108696",
|
||||
"locked_amount": "18206.796341262034809441102696",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "135173.4239508",
|
||||
@@ -1087,7 +1173,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "32499.86",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "6019.749088881220610994",
|
||||
"locked_amount": "5603.6958624323669808404",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "32499.86",
|
||||
@@ -1120,7 +1206,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "10833.29",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1959.369914168368365833",
|
||||
"locked_amount": "1823.94862624421256173",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10833.29",
|
||||
@@ -1153,7 +1239,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "22749.93",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "7324.562356528141179063",
|
||||
"locked_amount": "6818.3273364692396522472",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "6500",
|
||||
@@ -1291,8 +1377,8 @@
|
||||
"tranche_start": "2022-11-01T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-01T00:00:00.000Z",
|
||||
"total_added": "22500",
|
||||
"total_removed": "3853.26264195",
|
||||
"locked_amount": "10876.365389042358075",
|
||||
"total_removed": "3995.28612255",
|
||||
"locked_amount": "10348.030329189685875",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -1316,6 +1402,11 @@
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x702e76a6868be327dcce3416fa163759a406b68600063473106afdb555f03db4"
|
||||
},
|
||||
{
|
||||
"amount": "142.0234806",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x3f253311d975a353930c10981b742ac3b0df52da085d437244f077b63ec32953"
|
||||
},
|
||||
{
|
||||
"amount": "305.3119245",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -1391,6 +1482,12 @@
|
||||
"tranche_id": 33,
|
||||
"tx": "0x702e76a6868be327dcce3416fa163759a406b68600063473106afdb555f03db4"
|
||||
},
|
||||
{
|
||||
"amount": "142.0234806",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 33,
|
||||
"tx": "0x3f253311d975a353930c10981b742ac3b0df52da085d437244f077b63ec32953"
|
||||
},
|
||||
{
|
||||
"amount": "305.3119245",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -1453,8 +1550,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "7500",
|
||||
"withdrawn_tokens": "3853.26264195",
|
||||
"remaining_tokens": "3646.73735805"
|
||||
"withdrawn_tokens": "3995.28612255",
|
||||
"remaining_tokens": "3504.71387745"
|
||||
},
|
||||
{
|
||||
"address": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1",
|
||||
@@ -1479,7 +1576,7 @@
|
||||
"tranche_end": "2023-06-02T00:00:00.000Z",
|
||||
"total_added": "1939928.38",
|
||||
"total_removed": "928642.9598472029154",
|
||||
"locked_amount": "635097.0330095579571042166",
|
||||
"locked_amount": "612507.96463901900484135",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1852091.69",
|
||||
@@ -33440,7 +33537,7 @@
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "3732368.4671",
|
||||
"total_removed": "589730.8667090699299",
|
||||
"locked_amount": "1000424.34716318809300120353",
|
||||
"locked_amount": "965712.81375596155222172624",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1998.95815",
|
||||
@@ -34754,8 +34851,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "15870102.715470999700000001",
|
||||
"total_removed": "553068.12935216697830452",
|
||||
"locked_amount": "8847128.0872990775682462500282478416234118",
|
||||
"total_removed": "557133.30560592463281452",
|
||||
"locked_amount": "8724043.2185305122313058695420656514828332",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "16249.93",
|
||||
@@ -35294,6 +35391,31 @@
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x374feedb0a834a85c280bc2d0d021b727c4d7b303ac035bca381e1f1e7cd662e"
|
||||
},
|
||||
{
|
||||
"amount": "642.55098061144375",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xe01c0b55950dd8fbc43b42e45e486ae30b2114869a93294f66a0395d9700a157"
|
||||
},
|
||||
{
|
||||
"amount": "1181.60422182699945",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
"tx": "0x0817f7d1dd8b4931d3d72c2200528a68931366595a0ab42c1f02506552ae9f02"
|
||||
},
|
||||
{
|
||||
"amount": "983.56229747023875",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xcc454df031cba4b8a902fb6751d904e19e53a12263d500dcfe3c0bea079c9de8"
|
||||
},
|
||||
{
|
||||
"amount": "730.09381677206056",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
"tx": "0xb0d4e11c4f5aab1c4c65994c14d5272ecb4df9972ddee36ae5389de3731a3e35"
|
||||
},
|
||||
{
|
||||
"amount": "527.364937076912",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xa344428c2b1bf9b4685959441983da46bcd434ac0ee5ada325876c8733eba603"
|
||||
},
|
||||
{
|
||||
"amount": "858.360074993579125",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -36895,6 +37017,24 @@
|
||||
"tranche_id": 2,
|
||||
"tx": "0x374feedb0a834a85c280bc2d0d021b727c4d7b303ac035bca381e1f1e7cd662e"
|
||||
},
|
||||
{
|
||||
"amount": "642.55098061144375",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xe01c0b55950dd8fbc43b42e45e486ae30b2114869a93294f66a0395d9700a157"
|
||||
},
|
||||
{
|
||||
"amount": "983.56229747023875",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xcc454df031cba4b8a902fb6751d904e19e53a12263d500dcfe3c0bea079c9de8"
|
||||
},
|
||||
{
|
||||
"amount": "527.364937076912",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xa344428c2b1bf9b4685959441983da46bcd434ac0ee5ada325876c8733eba603"
|
||||
},
|
||||
{
|
||||
"amount": "858.360074993579125",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -37983,8 +38123,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "259998.8875",
|
||||
"withdrawn_tokens": "114813.26540279885025",
|
||||
"remaining_tokens": "145185.62209720114975"
|
||||
"withdrawn_tokens": "116966.74361795744475",
|
||||
"remaining_tokens": "143032.14388204255525"
|
||||
},
|
||||
{
|
||||
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
|
||||
@@ -38217,6 +38357,18 @@
|
||||
"tranche_id": 2,
|
||||
"tx": "0x137cf963adc7f889f2b24bb3d55716cb6b8581bf13040f13e65f1d16c52e2f9f"
|
||||
},
|
||||
{
|
||||
"amount": "1181.60422182699945",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x0817f7d1dd8b4931d3d72c2200528a68931366595a0ab42c1f02506552ae9f02"
|
||||
},
|
||||
{
|
||||
"amount": "730.09381677206056",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xb0d4e11c4f5aab1c4c65994c14d5272ecb4df9972ddee36ae5389de3731a3e35"
|
||||
},
|
||||
{
|
||||
"amount": "1293.67099136315494",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
@@ -38417,8 +38569,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "150551.801",
|
||||
"withdrawn_tokens": "65760.67703228632158",
|
||||
"remaining_tokens": "84791.12396771367842"
|
||||
"withdrawn_tokens": "67672.37507088538159",
|
||||
"remaining_tokens": "82879.42592911461841"
|
||||
},
|
||||
{
|
||||
"address": "0x4d982Ab0823fD2f48e934a7be2bb0a5374a26148",
|
||||
@@ -40155,8 +40307,8 @@
|
||||
"tranche_start": "2021-11-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-05T00:00:00.000Z",
|
||||
"total_added": "14597706.0446472999",
|
||||
"total_removed": "3711762.46803043411726343",
|
||||
"locked_amount": "2446166.93445800685782748312503739",
|
||||
"total_removed": "3920990.096830703963164282",
|
||||
"locked_amount": "2332535.769515174096512550505057687",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129284.449",
|
||||
@@ -40380,6 +40532,41 @@
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x0552a16f5a65f3ea47db290b80f164d6553717dd735e73bb0429b81e17bbbb3e"
|
||||
},
|
||||
{
|
||||
"amount": "21866.26138234560055572",
|
||||
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
|
||||
"tx": "0x99ef8fa79957e58f7b84adaf383bbd1bd19f9850a8e151b9d9822dd0aa102ba2"
|
||||
},
|
||||
{
|
||||
"amount": "892.784306759125222",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x2f991e6e03148ea102fe9c5586aa0e652e2dcc0b92a4db18edd58ba1a52eb00d"
|
||||
},
|
||||
{
|
||||
"amount": "61457.697291116421665635",
|
||||
"user": "0x35022e6c85B50F4904C7BC7e692A9F3bbEE8D2CE",
|
||||
"tx": "0x04da96101bf976dd51e21e038b061c7c161100c02b4e60e0d81a3a56ab01761d"
|
||||
},
|
||||
{
|
||||
"amount": "61457.922157658140165533",
|
||||
"user": "0x534200f54E753D998F9C2984B5971e4DB490e56F",
|
||||
"tx": "0x91774e0eddcd67a828be4320fd596eef753a6f216c89fe0c2c3e6407f0b44559"
|
||||
},
|
||||
{
|
||||
"amount": "61458.259458207381442714",
|
||||
"user": "0x85E14d90C63f70421a098AC26a5aCaB3854a1ee8",
|
||||
"tx": "0x188c440997a39f63e688188099b8ac5ab0829e77386de239026f0152f2de4f78"
|
||||
},
|
||||
{
|
||||
"amount": "1363.61315668407184225",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xf85cd1afadb4ab0505bd1a1c7accfaf89e466772a241ee0990deb678334bc27b"
|
||||
},
|
||||
{
|
||||
"amount": "731.091047499105007",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xc73c47dcfac4093bb6325fe92986dd010d5a773af4bb97e188ad57359a309a52"
|
||||
},
|
||||
{
|
||||
"amount": "8950.14985089483210984",
|
||||
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
|
||||
@@ -43199,6 +43386,24 @@
|
||||
"tranche_id": 3,
|
||||
"tx": "0x0552a16f5a65f3ea47db290b80f164d6553717dd735e73bb0429b81e17bbbb3e"
|
||||
},
|
||||
{
|
||||
"amount": "892.784306759125222",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x2f991e6e03148ea102fe9c5586aa0e652e2dcc0b92a4db18edd58ba1a52eb00d"
|
||||
},
|
||||
{
|
||||
"amount": "1363.61315668407184225",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xf85cd1afadb4ab0505bd1a1c7accfaf89e466772a241ee0990deb678334bc27b"
|
||||
},
|
||||
{
|
||||
"amount": "731.091047499105007",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xc73c47dcfac4093bb6325fe92986dd010d5a773af4bb97e188ad57359a309a52"
|
||||
},
|
||||
{
|
||||
"amount": "1192.05386354121365675",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@@ -45589,8 +45794,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "359123.469575",
|
||||
"withdrawn_tokens": "298604.4155492129604925",
|
||||
"remaining_tokens": "60519.0540257870395075"
|
||||
"withdrawn_tokens": "301591.90406015526256375",
|
||||
"remaining_tokens": "57531.56551484473743625"
|
||||
},
|
||||
{
|
||||
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
|
||||
@@ -45733,10 +45938,17 @@
|
||||
"tx": "0xa1445d0e6b158cc251e40952257cc3ccbab6cb63fd82c45761148510dfc0ec61"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "61458.259458207381442714",
|
||||
"user": "0x85E14d90C63f70421a098AC26a5aCaB3854a1ee8",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x188c440997a39f63e688188099b8ac5ab0829e77386de239026f0152f2de4f78"
|
||||
}
|
||||
],
|
||||
"total_tokens": "73666.3527333333",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "73666.3527333333"
|
||||
"withdrawn_tokens": "61458.259458207381442714",
|
||||
"remaining_tokens": "12208.093275125918557286"
|
||||
},
|
||||
{
|
||||
"address": "0xcc2cf726A84e71301f9079FC177BA946aa98A694",
|
||||
@@ -45813,6 +46025,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "21866.26138234560055572",
|
||||
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x99ef8fa79957e58f7b84adaf383bbd1bd19f9850a8e151b9d9822dd0aa102ba2"
|
||||
},
|
||||
{
|
||||
"amount": "8950.14985089483210984",
|
||||
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
|
||||
@@ -46133,8 +46351,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "1266324.603486",
|
||||
"withdrawn_tokens": "1032849.1990853972736093",
|
||||
"remaining_tokens": "233475.4044006027263907"
|
||||
"withdrawn_tokens": "1054715.46046774287416502",
|
||||
"remaining_tokens": "211609.14301825712583498"
|
||||
},
|
||||
{
|
||||
"address": "0xC5d9221EB9c28A69859264c0A2Fe0d3272228296",
|
||||
@@ -46294,10 +46512,17 @@
|
||||
"tx": "0x1d497efca56500bee594a6dfbbee65b1ceb2a59a840577febfe116f465b59504"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "61457.697291116421665635",
|
||||
"user": "0x35022e6c85B50F4904C7BC7e692A9F3bbEE8D2CE",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x04da96101bf976dd51e21e038b061c7c161100c02b4e60e0d81a3a56ab01761d"
|
||||
}
|
||||
],
|
||||
"total_tokens": "73666.3527333333",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "73666.3527333333"
|
||||
"withdrawn_tokens": "61457.697291116421665635",
|
||||
"remaining_tokens": "12208.655442216878334365"
|
||||
},
|
||||
{
|
||||
"address": "0xC62BC272187e0Fd48ed126B99ABD6e7943707E64",
|
||||
@@ -46391,10 +46616,17 @@
|
||||
"tx": "0x1626b2d31729ad9ef3d9d2f939fcc08c3d0205319a93ad33a7c4003731357309"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "61457.922157658140165533",
|
||||
"user": "0x534200f54E753D998F9C2984B5971e4DB490e56F",
|
||||
"tranche_id": 3,
|
||||
"tx": "0x91774e0eddcd67a828be4320fd596eef753a6f216c89fe0c2c3e6407f0b44559"
|
||||
}
|
||||
],
|
||||
"total_tokens": "73666.3527333333",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "73666.3527333333"
|
||||
"withdrawn_tokens": "61457.922157658140165533",
|
||||
"remaining_tokens": "12208.430575675159834467"
|
||||
},
|
||||
{
|
||||
"address": "0x4020DC404D9470E0F08D2E7A8d6eBc54035CF42C",
|
||||
@@ -46900,8 +47132,8 @@
|
||||
"tranche_start": "2021-10-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "5778205.3912159303",
|
||||
"total_removed": "2720584.477569657792162642",
|
||||
"locked_amount": "649591.946558625470488911658628152",
|
||||
"total_removed": "2730068.739915456784546642",
|
||||
"locked_amount": "604695.586054148570133080743399363",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "552496.6455",
|
||||
@@ -47075,6 +47307,16 @@
|
||||
"user": "0x6ae83EAB68b7112BaD5AfD72d6B24546AbFF137D",
|
||||
"tx": "0x47eb4c897187630f558845180b019d4c5c1816efd91abf3db4964ed14eea5efd"
|
||||
},
|
||||
{
|
||||
"amount": "5240.955854504870917",
|
||||
"user": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75",
|
||||
"tx": "0x936296f4bc21595778c766441b849f6f5a53f5b52fded7866703d276f137ff10"
|
||||
},
|
||||
{
|
||||
"amount": "4243.306491294121467",
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
"tx": "0x3dee2b22695a6bd2cf3925945ecac7b84cb3cf5b65113fc8af355a8fcce3c49d"
|
||||
},
|
||||
{
|
||||
"amount": "3634.58269967002683",
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
@@ -47960,6 +48202,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "5240.955854504870917",
|
||||
"user": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75",
|
||||
"tranche_id": 4,
|
||||
"tx": "0x936296f4bc21595778c766441b849f6f5a53f5b52fded7866703d276f137ff10"
|
||||
},
|
||||
{
|
||||
"amount": "11863.408335178645863",
|
||||
"user": "0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75",
|
||||
@@ -48052,8 +48300,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "110499.5291",
|
||||
"withdrawn_tokens": "93566.506422699926443",
|
||||
"remaining_tokens": "16933.022677300073557"
|
||||
"withdrawn_tokens": "98807.46227720479736",
|
||||
"remaining_tokens": "11692.06682279520264"
|
||||
},
|
||||
{
|
||||
"address": "0xdbC5d439F373EB646345e1c67D1d46231ACE7dD3",
|
||||
@@ -48535,6 +48783,12 @@
|
||||
"tranche_id": 4,
|
||||
"tx": "0x687f74292db1a9d0c79bedca56eb5dd57d5d338a2d536b355cd2d1022dc4889b"
|
||||
},
|
||||
{
|
||||
"amount": "4243.306491294121467",
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
"tranche_id": 4,
|
||||
"tx": "0x3dee2b22695a6bd2cf3925945ecac7b84cb3cf5b65113fc8af355a8fcce3c49d"
|
||||
},
|
||||
{
|
||||
"amount": "3634.58269967002683",
|
||||
"user": "0xafa64cCa337eFEE0AD827F6C2684e69275226e90",
|
||||
@@ -48765,8 +49019,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "331498.5873",
|
||||
"withdrawn_tokens": "292494.46862336024442",
|
||||
"remaining_tokens": "39004.11867663975558"
|
||||
"withdrawn_tokens": "296737.775114654365887",
|
||||
"remaining_tokens": "34760.812185345634113"
|
||||
},
|
||||
{
|
||||
"address": "0x16da609341ed67750A8BCC5AAa2005471006Cd77",
|
||||
@@ -48861,8 +49115,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "472355.6199999996",
|
||||
"total_removed": "31923.1301021472685",
|
||||
"locked_amount": "158522.95647737743991233846067988",
|
||||
"total_removed": "32361.4666889012685",
|
||||
"locked_amount": "153022.71558941830041836828209032",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "3000",
|
||||
@@ -55501,6 +55755,26 @@
|
||||
"user": "0x7C8D2D8BcFffcD48dBcb65C5Bb7588B66dcD22bb",
|
||||
"tx": "0x2883648c0fa0f5a27defb406ab22bc0120d43e3a98b16fd7a97d99f9e79dc24c"
|
||||
},
|
||||
{
|
||||
"amount": "133.62069381",
|
||||
"user": "0xfFdd56a550Cd388071a485f9331c46BeF652eC28",
|
||||
"tx": "0xd3f93705d1ddd14d480fa9e298d4f942efe21feebba8a64d1ba5bd2d01c8ceb3"
|
||||
},
|
||||
{
|
||||
"amount": "133.64984145",
|
||||
"user": "0x3616Dc96aBA2113B5E96E3B27fA61E0F0444cDe0",
|
||||
"tx": "0x45a4a7b7d6ba5248f574539e60389d8f758ac92791d8e7ac1d6c6f8fbc0b9e9c"
|
||||
},
|
||||
{
|
||||
"amount": "133.654027142",
|
||||
"user": "0x7D7219bA97d4d9F5135cd7c489e407bB1EAa0A1E",
|
||||
"tx": "0xcf9db8b982712a77cec727a423116897853a3180515f285d07ecc16c1d7e1634"
|
||||
},
|
||||
{
|
||||
"amount": "37.412024352",
|
||||
"user": "0x0e199b123f71f964d6567869B6B849C1f255A855",
|
||||
"tx": "0x6df8666e49f7d491c740d6a36df031aac232a6cf37fa197aa1f6b2bb481be99c"
|
||||
},
|
||||
{
|
||||
"amount": "78.261187214",
|
||||
"user": "0x479F059c46c6873C6B970A92911084b3eA036d56",
|
||||
@@ -62388,10 +62662,17 @@
|
||||
"tx": "0x75de6ca47e0da361181d14aceb5d08e572754861465caa67a12b528886d55307"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "133.64984145",
|
||||
"user": "0x3616Dc96aBA2113B5E96E3B27fA61E0F0444cDe0",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x45a4a7b7d6ba5248f574539e60389d8f758ac92791d8e7ac1d6c6f8fbc0b9e9c"
|
||||
}
|
||||
],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "200"
|
||||
"withdrawn_tokens": "133.64984145",
|
||||
"remaining_tokens": "66.35015855"
|
||||
},
|
||||
{
|
||||
"address": "0x55795BCA099a03A3619447c351BBd1f4E20Ee15f",
|
||||
@@ -62418,10 +62699,17 @@
|
||||
"tx": "0x75de6ca47e0da361181d14aceb5d08e572754861465caa67a12b528886d55307"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "133.62069381",
|
||||
"user": "0xfFdd56a550Cd388071a485f9331c46BeF652eC28",
|
||||
"tranche_id": 5,
|
||||
"tx": "0xd3f93705d1ddd14d480fa9e298d4f942efe21feebba8a64d1ba5bd2d01c8ceb3"
|
||||
}
|
||||
],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "200"
|
||||
"withdrawn_tokens": "133.62069381",
|
||||
"remaining_tokens": "66.37930619"
|
||||
},
|
||||
{
|
||||
"address": "0x7D7219bA97d4d9F5135cd7c489e407bB1EAa0A1E",
|
||||
@@ -62433,10 +62721,17 @@
|
||||
"tx": "0x75de6ca47e0da361181d14aceb5d08e572754861465caa67a12b528886d55307"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "133.654027142",
|
||||
"user": "0x7D7219bA97d4d9F5135cd7c489e407bB1EAa0A1E",
|
||||
"tranche_id": 5,
|
||||
"tx": "0xcf9db8b982712a77cec727a423116897853a3180515f285d07ecc16c1d7e1634"
|
||||
}
|
||||
],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "200"
|
||||
"withdrawn_tokens": "133.654027142",
|
||||
"remaining_tokens": "66.345972858"
|
||||
},
|
||||
{
|
||||
"address": "0x31410FE9199081BAA0a119E2c78Ecd42ca5130ce",
|
||||
@@ -72609,6 +72904,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "37.412024352",
|
||||
"user": "0x0e199b123f71f964d6567869B6B849C1f255A855",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x6df8666e49f7d491c740d6a36df031aac232a6cf37fa197aa1f6b2bb481be99c"
|
||||
},
|
||||
{
|
||||
"amount": "32.098173516",
|
||||
"user": "0x0e199b123f71f964d6567869B6B849C1f255A855",
|
||||
@@ -72659,8 +72960,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "400",
|
||||
"withdrawn_tokens": "232.628602232",
|
||||
"remaining_tokens": "167.371397768"
|
||||
"withdrawn_tokens": "270.040626584",
|
||||
"remaining_tokens": "129.959373416"
|
||||
},
|
||||
{
|
||||
"address": "0x74Da54F44975a1C224ABb5CAB8e5fc38a268B425",
|
||||
@@ -77393,7 +77694,7 @@
|
||||
"tranche_start": "2021-12-05T00:00:00.000Z",
|
||||
"tranche_end": "2022-06-05T00:00:00.000Z",
|
||||
"total_added": "171288.42",
|
||||
"total_removed": "64726.1049690697989",
|
||||
"total_removed": "65326.1049690697989",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@@ -81633,6 +81934,21 @@
|
||||
"user": "0x68091918EaDB98f54E8fC179870aB6F755736174",
|
||||
"tx": "0x6957558e2c90b17cd1ef8673ca4a6c949dfcdf0772e3b580e7dda2655b647c64"
|
||||
},
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x398596bD9Bb33db205B84744DFB20B6Ffbab20a3",
|
||||
"tx": "0x84eb91957cae169a0d11ed3205f39642ed71d8d185bd505ad80a02c8af48742d"
|
||||
},
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x7D7219bA97d4d9F5135cd7c489e407bB1EAa0A1E",
|
||||
"tx": "0x5dad4ba5a483a5807481d36612ff51aad8a99d4381a99674f3cf10d7b0936af3"
|
||||
},
|
||||
{
|
||||
"amount": "100",
|
||||
"user": "0x15E1A3cA96D92e621cdFb305fF86672A91309652",
|
||||
"tx": "0xbe66b488288b3c8422f192bdeb196e84361215b5125257e57c30cb3568bd6d3e"
|
||||
},
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0xbd09687340A09BeB0B5EE0D3C2bCa8d78eBF6E63",
|
||||
@@ -88782,10 +89098,17 @@
|
||||
"tx": "0x75de6ca47e0da361181d14aceb5d08e572754861465caa67a12b528886d55307"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x398596bD9Bb33db205B84744DFB20B6Ffbab20a3",
|
||||
"tranche_id": 6,
|
||||
"tx": "0x84eb91957cae169a0d11ed3205f39642ed71d8d185bd505ad80a02c8af48742d"
|
||||
}
|
||||
],
|
||||
"total_tokens": "250",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "250"
|
||||
"withdrawn_tokens": "250",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x52D4356fb92e1b42E7eb00e3d146e71715D6a3B8",
|
||||
@@ -88812,10 +89135,17 @@
|
||||
"tx": "0x75de6ca47e0da361181d14aceb5d08e572754861465caa67a12b528886d55307"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "250",
|
||||
"user": "0x7D7219bA97d4d9F5135cd7c489e407bB1EAa0A1E",
|
||||
"tranche_id": 6,
|
||||
"tx": "0x5dad4ba5a483a5807481d36612ff51aad8a99d4381a99674f3cf10d7b0936af3"
|
||||
}
|
||||
],
|
||||
"total_tokens": "250",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "250"
|
||||
"withdrawn_tokens": "250",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x9B99271c944B54e5cCc646526B990a34570A2660",
|
||||
@@ -89095,10 +89425,17 @@
|
||||
"tx": "0xc7dd4c2b995cc486fcd8b7892cd79f8fb393ada004dc68cf66ec82d99b35763c"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "100",
|
||||
"user": "0x15E1A3cA96D92e621cdFb305fF86672A91309652",
|
||||
"tranche_id": 6,
|
||||
"tx": "0xbe66b488288b3c8422f192bdeb196e84361215b5125257e57c30cb3568bd6d3e"
|
||||
}
|
||||
],
|
||||
"total_tokens": "100",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "100"
|
||||
"withdrawn_tokens": "100",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x460d9FAC558e889A62670DE75f42602BEfd5352D",
|
||||
@@ -131324,7 +131661,7 @@
|
||||
"tranche_start": "2021-11-05T00:00:00.000Z",
|
||||
"tranche_end": "2021-11-05T00:00:00.000Z",
|
||||
"total_added": "2576065.7689906998",
|
||||
"total_removed": "1693544.623694831",
|
||||
"total_removed": "1732544.457494831",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
@@ -131534,6 +131871,21 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "12999.9446",
|
||||
"user": "0x35022e6c85B50F4904C7BC7e692A9F3bbEE8D2CE",
|
||||
"tx": "0xe75811dc3d3bcb569fffd47a7639a0789fbb7fdf76fe07be66b80c34cac48476"
|
||||
},
|
||||
{
|
||||
"amount": "12999.9446",
|
||||
"user": "0x534200f54E753D998F9C2984B5971e4DB490e56F",
|
||||
"tx": "0xcfa366efafa255d261b11a868fea469454003be965aa279e6e605f912da55a36"
|
||||
},
|
||||
{
|
||||
"amount": "12999.9446",
|
||||
"user": "0x85E14d90C63f70421a098AC26a5aCaB3854a1ee8",
|
||||
"tx": "0x1e875503f81ad9c687c06338ae24cf6e307d3ab1a0407f3b3580134aa5254d66"
|
||||
},
|
||||
{
|
||||
"amount": "12187.4480625",
|
||||
"user": "0x4020DC404D9470E0F08D2E7A8d6eBc54035CF42C",
|
||||
@@ -132036,10 +132388,17 @@
|
||||
"tx": "0xe2f38513b930cc0039c228a3f2874b14e0ff51ff8665fc85497e312cf2a7cc1f"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "12999.9446",
|
||||
"user": "0x534200f54E753D998F9C2984B5971e4DB490e56F",
|
||||
"tranche_id": 8,
|
||||
"tx": "0xcfa366efafa255d261b11a868fea469454003be965aa279e6e605f912da55a36"
|
||||
}
|
||||
],
|
||||
"total_tokens": "12999.9446",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "12999.9446"
|
||||
"withdrawn_tokens": "12999.9446",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x91715128a71c9C734CDC20E5EdEEeA02E72e428E",
|
||||
@@ -132280,10 +132639,17 @@
|
||||
"tx": "0x28f48e77f8836299841824f7a0bcd610aeb626ab2dc1fdea9295989ab13e69d0"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "12999.9446",
|
||||
"user": "0x85E14d90C63f70421a098AC26a5aCaB3854a1ee8",
|
||||
"tranche_id": 8,
|
||||
"tx": "0x1e875503f81ad9c687c06338ae24cf6e307d3ab1a0407f3b3580134aa5254d66"
|
||||
}
|
||||
],
|
||||
"total_tokens": "12999.9446",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "12999.9446"
|
||||
"withdrawn_tokens": "12999.9446",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x37fBC48109c4D71Bb0FFD44Bef0FE493b9Ff582a",
|
||||
@@ -132310,10 +132676,17 @@
|
||||
"tx": "0x8d2d46bb9e5aff5dde2d68a98adc25efaaa35742cb22299db3c3ea01b8725516"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "12999.9446",
|
||||
"user": "0x35022e6c85B50F4904C7BC7e692A9F3bbEE8D2CE",
|
||||
"tranche_id": 8,
|
||||
"tx": "0xe75811dc3d3bcb569fffd47a7639a0789fbb7fdf76fe07be66b80c34cac48476"
|
||||
}
|
||||
],
|
||||
"total_tokens": "12999.9446",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "12999.9446"
|
||||
"withdrawn_tokens": "12999.9446",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x4020DC404D9470E0F08D2E7A8d6eBc54035CF42C",
|
||||
|
||||
+1
-1
@@ -16,7 +16,6 @@ NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
#Test configuration variables
|
||||
CYPRESS_FAIRGROUND=false
|
||||
CYPRESS_VEGA_URL=http://localhost:3028/query
|
||||
CYPRESS_VEGA_WALLET_API_TOKEN=jpeAkxcffzTLCzBX2m5TZIp3hF500YZhHwESwNKOGksdGPXeeIznXypaDfpNe2M9
|
||||
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
|
||||
@@ -29,3 +28,4 @@ CYPRESS_VEGA_PUBLIC_KEY2=7f9cf07d3a9905b1a61a1069f7a758855da428bc0f4a97de87f4864
|
||||
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=
|
||||
|
||||
@@ -37,8 +37,8 @@ context(
|
||||
function () {
|
||||
cy.reload();
|
||||
cy.wait_for_spinner();
|
||||
cy.connectVegaWallet();
|
||||
cy.ethereum_wallet_connect();
|
||||
cy.connectVegaWallet();
|
||||
cy.vega_wallet_teardown();
|
||||
cy.navigate_to('validators');
|
||||
}
|
||||
@@ -57,7 +57,16 @@ context(
|
||||
//0005-ETXN-006
|
||||
//0005-ETXN-003
|
||||
//0005-ETXN-005
|
||||
cy.staking_page_associate_tokens('2');
|
||||
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);
|
||||
|
||||
// 0005-ETXN-002
|
||||
cy.get(ethWalletAssociatedBalances, txTimeout)
|
||||
@@ -98,6 +107,15 @@ 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)
|
||||
@@ -194,7 +212,19 @@ context(
|
||||
// 1004-ASSO-024
|
||||
// 1004-ASSO-023
|
||||
|
||||
cy.staking_page_associate_tokens('2', { type: 'contract' });
|
||||
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.get(ethWalletAssociatedBalances, txTimeout)
|
||||
.contains(vegaWalletPublicKeyShort)
|
||||
@@ -210,7 +240,19 @@ context(
|
||||
});
|
||||
|
||||
cy.get(vegaWalletUnstakedBalance, txTimeout).should('contain', 2.0);
|
||||
cy.staking_page_disassociate_tokens('1', { type: 'contract' });
|
||||
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.get(ethWalletAssociatedBalances, txTimeout)
|
||||
.contains(vegaWalletPublicKeyShort)
|
||||
@@ -286,6 +328,35 @@ 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();
|
||||
@@ -310,6 +381,7 @@ context(
|
||||
'vegaWalletPublicKey2Short'
|
||||
)} can now participate in governance and nominate a validator with your associated $VEGA.`
|
||||
);
|
||||
cy.staking_page_disassociate_all_tokens();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -321,6 +321,8 @@ context(
|
||||
'200000',
|
||||
vegaWalletPublicKey
|
||||
);
|
||||
cy.reload();
|
||||
cy.wait_for_spinner();
|
||||
cy.connectVegaWallet();
|
||||
cy.ethereum_wallet_connect();
|
||||
});
|
||||
|
||||
@@ -58,6 +58,8 @@ 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();
|
||||
@@ -79,16 +81,19 @@ Cypress.Commands.add('staking_page_associate_tokens', (amount, options) => {
|
||||
);
|
||||
}
|
||||
cy.get(tokenSubmitButton, txTimeout).should('be.enabled').click();
|
||||
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');
|
||||
|
||||
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');
|
||||
}
|
||||
});
|
||||
|
||||
Cypress.Commands.add('staking_page_disassociate_tokens', (amount, options) => {
|
||||
@@ -216,3 +221,19 @@ 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,7 +8,6 @@ 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');
|
||||
@@ -43,6 +42,11 @@ 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
|
||||
@@ -91,29 +95,18 @@ 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(
|
||||
@@ -176,6 +169,22 @@ 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 });
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ 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';
|
||||
@@ -88,14 +89,14 @@ const Web3Container = ({
|
||||
<AppLoader>
|
||||
<BalanceManager>
|
||||
<>
|
||||
<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">
|
||||
<AppLayout>
|
||||
<TemplateSidebar sidebar={sideBar}>
|
||||
<AppRouter />
|
||||
</TemplateSidebar>
|
||||
<footer className="p-4 border-t border-neutral-700">
|
||||
<NetworkInfo />
|
||||
</footer>
|
||||
</div>
|
||||
</AppLayout>
|
||||
<VegaWalletDialogs />
|
||||
<TransactionModal />
|
||||
<WithdrawalDialog />
|
||||
|
||||
@@ -18,7 +18,7 @@ export const NavDropDown = ({ navbarTheme }: { navbarTheme: NavbarTheme }) => {
|
||||
<AppNavLink
|
||||
name={
|
||||
<NavDropdownMenuTrigger
|
||||
className="w-auto text-capMenu"
|
||||
className="w-auto flex items-center"
|
||||
data-testid="state-trigger"
|
||||
onClick={() => setOpen(!isOpen)}
|
||||
>
|
||||
@@ -38,6 +38,7 @@ export const NavDropDown = ({ navbarTheme }: { navbarTheme: NavbarTheme }) => {
|
||||
name={t(r.name)}
|
||||
path={r.path}
|
||||
navbarTheme={'inherit'}
|
||||
subNav={true}
|
||||
end={true}
|
||||
fullWidth={true}
|
||||
/>
|
||||
|
||||
@@ -13,6 +13,7 @@ interface AppNavLinkProps {
|
||||
target?: HTMLAttributeAnchorTarget;
|
||||
end?: boolean;
|
||||
fullWidth?: boolean;
|
||||
subNav?: boolean;
|
||||
}
|
||||
|
||||
export const AppNavLink = ({
|
||||
@@ -23,28 +24,32 @@ export const AppNavLink = ({
|
||||
testId,
|
||||
end = false,
|
||||
fullWidth = false,
|
||||
subNav = false,
|
||||
}: AppNavLinkProps) => {
|
||||
const borderClasses = classNames('absolute h-1 w-full bottom-[-1px] left-0', {
|
||||
'bg-black dark:bg-vega-yellow': navbarTheme !== 'yellow',
|
||||
'bg-black': navbarTheme === 'yellow',
|
||||
});
|
||||
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',
|
||||
}
|
||||
);
|
||||
return (
|
||||
<NavLink
|
||||
key={path}
|
||||
data-testid={testId}
|
||||
to={{ pathname: path }}
|
||||
className={getNavLinkClassNames(navbarTheme, fullWidth)}
|
||||
className={getNavLinkClassNames(navbarTheme, fullWidth, subNav)}
|
||||
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,9 +22,8 @@ const renderComponent = (initialEntries?: string[]) => {
|
||||
};
|
||||
|
||||
describe('nav', () => {
|
||||
it('Renders title and logo with link to home', () => {
|
||||
it('Renders logo with link to home', () => {
|
||||
renderComponent();
|
||||
expect(screen.getByText('Governance')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('logo-link')).toHaveProperty(
|
||||
'href',
|
||||
'http://localhost/'
|
||||
|
||||
@@ -3,7 +3,8 @@ import { NetworkSwitcher } from '@vegaprotocol/environment';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { TOP_LEVEL_ROUTES } from '../../routes/routes';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import vegaWhite from '../../images/vega_white.png';
|
||||
import logoWhiteText from '../../images/logo-white-text.png';
|
||||
import logoBlackText from '../../images/logo-black-text.png';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { NavDrawer } from './nav-draw';
|
||||
import { Nav as ToolkitNav } from '@vegaprotocol/ui-toolkit';
|
||||
@@ -46,14 +47,19 @@ export const Nav = ({ navbarTheme = 'inherit' }: NavbarProps) => {
|
||||
navbarTheme={navbarTheme}
|
||||
icon={
|
||||
<Link to="/" data-testid="logo-link">
|
||||
<img alt="Vega" src={vegaWhite} height={30} width={30} />
|
||||
<img
|
||||
alt="Vega"
|
||||
src={navbarTheme === 'yellow' ? logoBlackText : logoWhiteText}
|
||||
height={30}
|
||||
width={250}
|
||||
/>
|
||||
</Link>
|
||||
}
|
||||
title={t('Governance')}
|
||||
title={undefined}
|
||||
titleContent={<NetworkSwitcher />}
|
||||
>
|
||||
{isDesktop ? (
|
||||
<nav className="flex items-center flex-1 px-2">
|
||||
<nav className="flex items-center flex-1 px-4">
|
||||
{TOP_LEVEL_ROUTES.map((r) => (
|
||||
<AppNavLink
|
||||
key={r.path}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
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>;
|
||||
};
|
||||
@@ -30,9 +30,7 @@ export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
|
||||
<Nav navbarTheme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'} />
|
||||
{isReadOnly ? (
|
||||
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
) : null}
|
||||
<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">
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
@@ -177,7 +177,7 @@ interface TotalPenaltiesRendererProps {
|
||||
performanceScore: string;
|
||||
performancePenalty: string;
|
||||
overstakedAmount: string;
|
||||
overstakedPenalty: string;
|
||||
overstakingPenalty: string;
|
||||
totalPenalties: string;
|
||||
};
|
||||
}
|
||||
@@ -192,20 +192,10 @@ export const TotalPenaltiesRenderer = ({
|
||||
description={
|
||||
<>
|
||||
<div>
|
||||
<span>
|
||||
{t('performancePenalty')}: {data.performancePenalty}
|
||||
</span>
|
||||
<span className="pl-2">
|
||||
({t('score')} {data.performanceScore})
|
||||
</span>
|
||||
{t('performancePenalty')}: {data.performancePenalty}
|
||||
</div>
|
||||
<div>
|
||||
<span>
|
||||
{t('overstakedPenalty')}: {data.overstakedPenalty}
|
||||
</span>
|
||||
<span className="pl-2">
|
||||
({t('overstaked')} {data.overstakedAmount})
|
||||
</span>
|
||||
{t('overstakedPenalty')}: {data.overstakingPenalty}
|
||||
</div>
|
||||
<div>
|
||||
{t('totalPenalties')}:{' '}
|
||||
|
||||
@@ -13,3 +13,9 @@
|
||||
@apply mb-2 text-neutral-400;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.border-default {
|
||||
@apply border-vega-dark-200;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,10 @@ 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';
|
||||
@@ -33,9 +36,112 @@ 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();
|
||||
@@ -128,13 +234,15 @@ 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(ordersTab).click();
|
||||
|
||||
cy.getByTestId(toastCloseBtn).click({ multiple: true });
|
||||
cy.getByTestId(ordersTab).click();
|
||||
cy.get('.ag-center-cols-container')
|
||||
.children()
|
||||
.first()
|
||||
@@ -164,62 +272,8 @@ 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-001
|
||||
// 1002-WITH-0014
|
||||
// 1002-WITH-006
|
||||
// 1002-WITH-009
|
||||
// 1002-WITH-011
|
||||
@@ -229,14 +283,18 @@ 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();
|
||||
cy.get(assetSelectField, txTimeout).select(
|
||||
'BTC (local)5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c - tBTC',
|
||||
{ force: true }
|
||||
);
|
||||
connectEthereumWallet('Unknown');
|
||||
cy.get(assetSelectField, txTimeout).select(btcName, { force: true });
|
||||
cy.get(amountField).clear().type('1');
|
||||
cy.getByTestId('submit-withdrawal').click();
|
||||
cy.getByTestId(toastContent, txTimeout).should(
|
||||
@@ -255,12 +313,13 @@ 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('complete-withdrawal', txTimeout).should('not.exist');
|
||||
cy.getByTestId(completeWithdrawalBtn).eq(0, txTimeout).should('not.exist');
|
||||
|
||||
cy.get('[col-id="txHash"]', txTimeout)
|
||||
.should('have.length.above', 1)
|
||||
@@ -281,9 +340,12 @@ 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('deposit - if approved amount is less than deposit: must see that an approval is needed and be prompted to approve more', function () {
|
||||
it('approved amount is less than deposit', function () {
|
||||
// 1001-DEPO-006
|
||||
|
||||
cy.getByTestId(depositsTab).click();
|
||||
@@ -292,6 +354,67 @@ 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,6 +4,7 @@ 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(() => {
|
||||
@@ -179,7 +180,8 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
'termination.BTC.value'
|
||||
);
|
||||
|
||||
cy.getByTestId(externalLink)
|
||||
cy.getByTestId(accordionContent)
|
||||
.find(`[data-testid="${externalLink}"]`)
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', '/oracles');
|
||||
});
|
||||
@@ -187,12 +189,14 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
it('proposal displayed', () => {
|
||||
cy.getByTestId(marketTitle).contains('Proposal').click();
|
||||
|
||||
cy.getByTestId(externalLink)
|
||||
cy.getByTestId(accordionContent)
|
||||
.find(`[data-testid="${externalLink}"]`)
|
||||
.first()
|
||||
.should('have.text', 'View governance proposal')
|
||||
.and('have.attr', 'href')
|
||||
.and('contain', '/proposals/market-0');
|
||||
cy.getByTestId(externalLink)
|
||||
cy.getByTestId(accordionContent)
|
||||
.find(`[data-testid="${externalLink}"]`)
|
||||
.eq(1)
|
||||
.should('have.text', 'Propose a change to market')
|
||||
.and('have.attr', 'href')
|
||||
|
||||
@@ -104,7 +104,8 @@ describe('markets table', { tags: '@smoke' }, () => {
|
||||
'have.length',
|
||||
10
|
||||
);
|
||||
cy.getByTestId('external-link')
|
||||
cy.getByTestId('tab-proposed-markets')
|
||||
.find('[data-testid="external-link"]')
|
||||
.should('have.length', 11)
|
||||
.last()
|
||||
.should('have.text', 'Propose a new market')
|
||||
|
||||
@@ -41,6 +41,7 @@ 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();
|
||||
@@ -50,6 +51,8 @@ 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();
|
||||
@@ -60,6 +63,7 @@ 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');
|
||||
@@ -68,6 +72,9 @@ 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(() => {
|
||||
@@ -88,6 +95,8 @@ 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',
|
||||
@@ -108,7 +117,4 @@ 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,3 +8,4 @@ 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,6 +9,7 @@ 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,3 +8,4 @@ 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,3 +7,4 @@ 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,4 +7,5 @@ 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_DOCS_URL=https://docs.vega.xyz/mainnet
|
||||
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
|
||||
|
||||
@@ -7,3 +7,4 @@ 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,3 +8,4 @@ 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,3 +8,4 @@ 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,3 +8,4 @@ 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
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
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
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useWithdrawalDialog } from '@vegaprotocol/withdraws';
|
||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { AccountManager } from '@vegaprotocol/accounts';
|
||||
import { AccountManager, useTransferDialog } from '@vegaprotocol/accounts';
|
||||
import { useDepositDialog } from '@vegaprotocol/deposits';
|
||||
|
||||
export const AccountsContainer = () => {
|
||||
@@ -13,6 +13,7 @@ export const AccountsContainer = () => {
|
||||
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) => {
|
||||
@@ -41,7 +42,10 @@ export const AccountsContainer = () => {
|
||||
/>
|
||||
</div>
|
||||
{!isReadOnly && (
|
||||
<div className="flex justify-end p-2 px-[11px]">
|
||||
<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>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './banner';
|
||||
@@ -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-start xl:flex-1 w-full overflow-x-auto text-xs"
|
||||
className="flex flex-nowrap items-end xl:flex-1 w-full overflow-x-auto text-xs"
|
||||
>
|
||||
{Children.map(children, (child, index) => {
|
||||
if (!child) return null;
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
useLinks,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { useGlobalStore } from '../../stores/global';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
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" navbarTheme={navbarTheme} />
|
||||
<LinkList className="hidden md:flex md:px-2" navbarTheme={navbarTheme} />
|
||||
<div className="flex items-center gap-2 ml-auto overflow-hidden">
|
||||
<VegaWalletConnectButton />
|
||||
<ThemeSwitcher className="hidden md:block" />
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { VegaTransaction } from './vega-transaction';
|
||||
@@ -1,57 +0,0 @@
|
||||
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,11 +13,13 @@ 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,
|
||||
@@ -30,6 +32,7 @@ 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);
|
||||
@@ -115,7 +118,16 @@ const MobileWalletButton = ({
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="m-4">
|
||||
<div className="flex flex-col gap-2 m-4">
|
||||
<Button
|
||||
onClick={() => {
|
||||
setDrawerOpen(false);
|
||||
openTransferDialog(true);
|
||||
}}
|
||||
fill
|
||||
>
|
||||
{t('Transfer')}
|
||||
</Button>
|
||||
<Button onClick={mobileDisconnect} fill>
|
||||
{t('Disconnect')}
|
||||
</Button>
|
||||
@@ -131,6 +143,7 @@ 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;
|
||||
|
||||
@@ -171,6 +184,10 @@ 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,8 +3,12 @@ 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, useMemo } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import compact from 'lodash/compact';
|
||||
import type { EthStoredTxState } from '@vegaprotocol/web3';
|
||||
import {
|
||||
@@ -44,34 +48,35 @@ const EthTransactionDetails = ({ tx }: { tx: EthStoredTxState }) => {
|
||||
if (isWithdraw) label = t('Withdraw');
|
||||
if (isDeposit) label = t('Deposit');
|
||||
assetInfo = (
|
||||
<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>
|
||||
<strong>
|
||||
{label}{' '}
|
||||
{formatNumber(toBigNum(tx.args[1], asset.decimals), asset.decimals)}{' '}
|
||||
{asset.symbol}
|
||||
</strong>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
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;
|
||||
};
|
||||
|
||||
type EthTxToastContentProps = {
|
||||
@@ -80,26 +85,26 @@ type EthTxToastContentProps = {
|
||||
|
||||
const EthTxRequestedToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
return (
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Action required')}</h3>
|
||||
<>
|
||||
<ToastHeading>{t('Action required')}</ToastHeading>
|
||||
<p>
|
||||
{t(
|
||||
'Please go to your wallet application and approve or reject the transaction.'
|
||||
)}
|
||||
</p>
|
||||
<EthTransactionDetails tx={tx} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const EthTxPendingToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
return (
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Awaiting confirmation')}</h3>
|
||||
<>
|
||||
<ToastHeading>{t('Awaiting confirmation')}</ToastHeading>
|
||||
<p>{t('Please wait for your transaction to be confirmed.')}</p>
|
||||
<EtherscanLink tx={tx} />
|
||||
<EthTransactionDetails tx={tx} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -112,11 +117,11 @@ const EthTxErrorToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
errorMessage = tx.error.message;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Error occurred')}</h3>
|
||||
<p>{errorMessage}</p>
|
||||
<>
|
||||
<ToastHeading>{t('Error occurred')}</ToastHeading>
|
||||
<p className="first-letter:uppercase">{errorMessage}</p>
|
||||
<EthTransactionDetails tx={tx} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -136,42 +141,63 @@ const EtherscanLink = ({ tx }: EthTxToastContentProps) => {
|
||||
|
||||
const EthTxConfirmedToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
return (
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Transaction confirmed')}</h3>
|
||||
<>
|
||||
<ToastHeading>{t('Transaction confirmed')}</ToastHeading>
|
||||
<p>{t('Your transaction has been confirmed.')}</p>
|
||||
<EtherscanLink tx={tx} />
|
||||
<EthTransactionDetails tx={tx} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const EthTxCompletedToastContent = ({ tx }: EthTxToastContentProps) => {
|
||||
const isDeposit = isDepositTransaction(tx);
|
||||
return (
|
||||
<div>
|
||||
<h3 className="font-bold">
|
||||
<>
|
||||
<ToastHeading>
|
||||
{t('Processing')} {isDeposit && t('deposit')}
|
||||
</h3>
|
||||
</ToastHeading>
|
||||
<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 ethTransactions = useEthTransactionStore((state) =>
|
||||
state.transactions.filter((transaction) => transaction?.dialogOpen)
|
||||
);
|
||||
const dismissEthTransaction = useEthTransactionStore(
|
||||
(state) => state.dismiss
|
||||
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 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} />;
|
||||
}
|
||||
@@ -191,15 +217,21 @@ export const useEthereumTransactionToasts = () => {
|
||||
return {
|
||||
id: `eth-${tx.id}`,
|
||||
intent: intentMap[tx.status],
|
||||
onClose: () => dismissEthTransaction(tx.id),
|
||||
onClose: onClose(tx),
|
||||
loader: [EthTxStatus.Pending, EthTxStatus.Complete].includes(tx.status),
|
||||
content,
|
||||
closeAfter,
|
||||
};
|
||||
},
|
||||
[dismissEthTransaction]
|
||||
[onClose]
|
||||
);
|
||||
|
||||
return useMemo(() => {
|
||||
return [...compact(ethTransactions).map(fromEthTransaction)];
|
||||
}, [ethTransactions, fromEthTransaction]);
|
||||
useEthTransactionStore.subscribe(
|
||||
(state) => compact(state.transactions.filter((tx) => tx?.dialogOpen)),
|
||||
(txs) => {
|
||||
txs.forEach((tx) => {
|
||||
setToast(fromEthTransaction(tx));
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
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, useMemo } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import compact from 'lodash/compact';
|
||||
import type { EthWithdrawalApprovalState } from '@vegaprotocol/web3';
|
||||
import { useEthWithdrawApprovalsStore } from '@vegaprotocol/web3';
|
||||
@@ -30,49 +34,72 @@ 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 = (
|
||||
<div className="mt-[5px]">
|
||||
<span className="font-mono text-xs p-1 bg-gray-100 rounded">
|
||||
<Panel>
|
||||
<strong>
|
||||
{t('Withdraw')} {num} {tx.withdrawal.asset.symbol}
|
||||
</span>
|
||||
</div>
|
||||
</strong>
|
||||
</Panel>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
{title.length > 0 && <h3 className="font-bold">{title}</h3>}
|
||||
<>
|
||||
{title.length > 0 && (
|
||||
<ToastHeading className="font-bold">{title}</ToastHeading>
|
||||
)}
|
||||
<VerificationStatus state={tx} />
|
||||
{details}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const isFinal = (tx: EthWithdrawalApprovalState) =>
|
||||
[ApprovalStatus.Ready, ApprovalStatus.Error].includes(tx.status);
|
||||
|
||||
export const useEthereumWithdrawApprovalsToasts = () => {
|
||||
const { withdrawApprovals, dismissWithdrawApproval } =
|
||||
useEthWithdrawApprovalsStore((state) => ({
|
||||
withdrawApprovals: state.transactions.filter(
|
||||
(transaction) => transaction?.dialogOpen
|
||||
),
|
||||
dismissWithdrawApproval: state.dismiss,
|
||||
}));
|
||||
const [setToast, remove] = useToasts((state) => [
|
||||
state.setToast,
|
||||
state.remove,
|
||||
]);
|
||||
const [dismissTx, deleteTx] = useEthWithdrawApprovalsStore((state) => [
|
||||
state.dismiss,
|
||||
state.delete,
|
||||
]);
|
||||
|
||||
const fromWithdrawalApproval = useCallback(
|
||||
(tx: EthWithdrawalApprovalState): Toast => ({
|
||||
id: `withdrawal-${tx.id}`,
|
||||
intent: intentMap[tx.status],
|
||||
onClose: () => dismissWithdrawApproval(tx.id),
|
||||
onClose: () => {
|
||||
if ([ApprovalStatus.Error, ApprovalStatus.Ready].includes(tx.status)) {
|
||||
deleteTx(tx.id);
|
||||
} else {
|
||||
dismissTx(tx.id);
|
||||
}
|
||||
remove(`withdrawal-${tx.id}`);
|
||||
},
|
||||
loader: tx.status === ApprovalStatus.Pending,
|
||||
content: <EthWithdrawalApprovalToastContent tx={tx} />,
|
||||
closeAfter: isFinal(tx) ? CLOSE_AFTER : undefined,
|
||||
}),
|
||||
[dismissWithdrawApproval]
|
||||
[deleteTx, dismissTx, remove]
|
||||
);
|
||||
|
||||
const toasts = useMemo(() => {
|
||||
return [...compact(withdrawApprovals).map(fromWithdrawalApproval)];
|
||||
}, [fromWithdrawalApproval, withdrawApprovals]);
|
||||
|
||||
return toasts;
|
||||
useEthWithdrawApprovalsStore.subscribe(
|
||||
(state) =>
|
||||
compact(
|
||||
state.transactions.filter((transaction) => transaction?.dialogOpen)
|
||||
),
|
||||
(txs) => {
|
||||
txs.forEach((tx) => {
|
||||
setToast(fromWithdrawalApproval(tx));
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -134,23 +134,7 @@ const submitOrder: VegaStoredTxState = {
|
||||
type: OrderType.TYPE_MARKET,
|
||||
price: '1234',
|
||||
createdAt: new Date(),
|
||||
market: {
|
||||
id: 'market-1',
|
||||
decimalPlaces: 2,
|
||||
positionDecimalPlaces: 2,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
code: 'M1',
|
||||
name: 'M1',
|
||||
product: {
|
||||
settlementAsset: {
|
||||
decimals: 2,
|
||||
symbol: '$A',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
marketId: 'market-1',
|
||||
status: OrderStatus.STATUS_ACTIVE,
|
||||
},
|
||||
};
|
||||
@@ -181,23 +165,7 @@ const editOrder: VegaStoredTxState = {
|
||||
type: OrderType.TYPE_MARKET,
|
||||
price: '1234',
|
||||
createdAt: new Date(),
|
||||
market: {
|
||||
id: 'market-1',
|
||||
decimalPlaces: 2,
|
||||
positionDecimalPlaces: 2,
|
||||
tradableInstrument: {
|
||||
instrument: {
|
||||
code: 'M1',
|
||||
name: 'M1',
|
||||
product: {
|
||||
settlementAsset: {
|
||||
decimals: 2,
|
||||
symbol: '$A',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
marketId: 'market-1',
|
||||
status: OrderStatus.STATUS_ACTIVE,
|
||||
},
|
||||
};
|
||||
@@ -292,7 +260,7 @@ describe('VegaTransactionDetails', () => {
|
||||
const { queryByTestId } = render(
|
||||
<VegaTransactionDetails tx={unsupportedTransaction} />
|
||||
);
|
||||
expect(queryByTestId('vega-tx-details')).toBeNull();
|
||||
expect(queryByTestId('toast-panel')).toBeNull();
|
||||
});
|
||||
it.each([
|
||||
{ tx: withdraw, details: 'Withdraw 12.34 $A' },
|
||||
@@ -307,6 +275,6 @@ describe('VegaTransactionDetails', () => {
|
||||
{ tx: batch, details: 'Batch market instruction' },
|
||||
])('display details for transaction', ({ tx, details }) => {
|
||||
const { queryByTestId } = render(<VegaTransactionDetails tx={tx} />);
|
||||
expect(queryByTestId('vega-tx-details')?.textContent).toEqual(details);
|
||||
expect(queryByTestId('toast-panel')?.textContent).toEqual(details);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import first from 'lodash/first';
|
||||
import compact from 'lodash/compact';
|
||||
import type {
|
||||
BatchMarketInstructionSubmissionBody,
|
||||
OrderAmendment,
|
||||
OrderBusEventFieldsFragment,
|
||||
OrderTxUpdateFieldsFragment,
|
||||
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,
|
||||
@@ -25,6 +24,10 @@ 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,
|
||||
@@ -32,14 +35,15 @@ 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 } = {
|
||||
@@ -78,29 +82,17 @@ 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
|
||||
batchMarketInstructions ||
|
||||
transfer
|
||||
);
|
||||
};
|
||||
|
||||
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;
|
||||
@@ -130,12 +122,10 @@ const SubmitOrderDetails = ({
|
||||
order,
|
||||
}: {
|
||||
data: OrderSubmission;
|
||||
order?: OrderBusEventFieldsFragment;
|
||||
order?: OrderTxUpdateFieldsFragment;
|
||||
}) => {
|
||||
const { data: markets } = useMarketList();
|
||||
const market = order
|
||||
? order.market
|
||||
: markets?.find((m) => m.id === data.marketId);
|
||||
const market = markets?.find((m) => m.id === order?.marketId);
|
||||
if (!market) return null;
|
||||
|
||||
const price = order ? order.price : data.price;
|
||||
@@ -143,8 +133,8 @@ const SubmitOrderDetails = ({
|
||||
const side = order ? order.side : data.side;
|
||||
|
||||
return (
|
||||
<Details>
|
||||
<h4 className="font-bold">
|
||||
<Panel>
|
||||
<h4>
|
||||
{order
|
||||
? t(
|
||||
`Submit order - ${OrderStatusMapping[order.status].toLowerCase()}`
|
||||
@@ -166,10 +156,7 @@ const SubmitOrderDetails = ({
|
||||
price={price}
|
||||
/>
|
||||
</p>
|
||||
{order && order.rejectionReason && (
|
||||
<p className="italic">{getRejectionReason(order)}</p>
|
||||
)}
|
||||
</Details>
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -178,16 +165,17 @@ const EditOrderDetails = ({
|
||||
order,
|
||||
}: {
|
||||
data: OrderAmendment;
|
||||
order?: OrderBusEventFieldsFragment;
|
||||
order?: OrderTxUpdateFieldsFragment;
|
||||
}) => {
|
||||
const { data: orderById } = useOrderByIdQuery({
|
||||
variables: { orderId: data.orderId },
|
||||
});
|
||||
const { data: markets } = useMarketList();
|
||||
|
||||
const originalOrder = orderById?.orderByID;
|
||||
const originalOrder = order || orderById?.orderByID;
|
||||
const marketId = order?.marketId || orderById?.orderByID.market.id;
|
||||
if (!originalOrder) return null;
|
||||
const market = markets?.find((m) => m.id === originalOrder.market.id);
|
||||
const market = markets?.find((m) => m.id === marketId);
|
||||
if (!market) return null;
|
||||
|
||||
const original = (
|
||||
@@ -219,8 +207,8 @@ const EditOrderDetails = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<Details title={data.orderId}>
|
||||
<h4 className="font-bold">
|
||||
<Panel title={data.orderId}>
|
||||
<h4>
|
||||
{order
|
||||
? t(`Edit order - ${OrderStatusMapping[order.status].toLowerCase()}`)
|
||||
: t('Edit order')}
|
||||
@@ -230,10 +218,7 @@ const EditOrderDetails = ({
|
||||
<s>{original}</s>
|
||||
</p>
|
||||
<p>{edited}</p>
|
||||
{order && order.rejectionReason && (
|
||||
<p className="italic">{getRejectionReason(order)}</p>
|
||||
)}
|
||||
</Details>
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -242,7 +227,7 @@ const CancelOrderDetails = ({
|
||||
order,
|
||||
}: {
|
||||
orderId: string;
|
||||
order?: OrderBusEventFieldsFragment;
|
||||
order?: OrderTxUpdateFieldsFragment;
|
||||
}) => {
|
||||
const { data: orderById } = useOrderByIdQuery({
|
||||
variables: { orderId },
|
||||
@@ -268,8 +253,8 @@ const CancelOrderDetails = ({
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<Details title={orderId}>
|
||||
<h4 className="font-bold">
|
||||
<Panel title={orderId}>
|
||||
<h4>
|
||||
{order
|
||||
? t(
|
||||
`Cancel order - ${OrderStatusMapping[order.status].toLowerCase()}`
|
||||
@@ -280,10 +265,7 @@ const CancelOrderDetails = ({
|
||||
<p>
|
||||
<s>{original}</s>
|
||||
</p>
|
||||
{order && order.rejectionReason && (
|
||||
<p className="italic">{getRejectionReason(order)}</p>
|
||||
)}
|
||||
</Details>
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -302,9 +284,11 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
|
||||
asset.decimals
|
||||
);
|
||||
return (
|
||||
<Details>
|
||||
{t('Withdraw')} {num} {asset.symbol}
|
||||
</Details>
|
||||
<Panel>
|
||||
<strong>
|
||||
{t('Withdraw')} {num} {asset.symbol}
|
||||
</strong>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -321,7 +305,7 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
|
||||
tx.body.orderCancellation.marketId === undefined &&
|
||||
tx.body.orderCancellation.orderId === undefined
|
||||
) {
|
||||
return <Details>{t('Cancel all orders')}</Details>;
|
||||
return <Panel>{t('Cancel all orders')}</Panel>;
|
||||
}
|
||||
|
||||
// CANCEL
|
||||
@@ -344,11 +328,15 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
|
||||
m.id === (tx.body as OrderCancellationBody).orderCancellation.marketId
|
||||
)?.tradableInstrument.instrument.code;
|
||||
return (
|
||||
<Details>
|
||||
{marketName
|
||||
? `${t('Cancel all orders for')} ${marketName}`
|
||||
: t('Cancel all orders')}
|
||||
</Details>
|
||||
<Panel>
|
||||
{marketName ? (
|
||||
<>
|
||||
{t('Cancel all orders for')} <strong>{marketName}</strong>
|
||||
</>
|
||||
) : (
|
||||
t('Cancel all orders')
|
||||
)}
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -370,15 +358,36 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
|
||||
const market = marketId && markets?.find((m) => m.id === marketId);
|
||||
if (market) {
|
||||
return (
|
||||
<Details>
|
||||
{t('Close position for')} {market.tradableInstrument.instrument.code}
|
||||
</Details>
|
||||
<Panel>
|
||||
{t('Close position for')}{' '}
|
||||
<strong>{market.tradableInstrument.instrument.code}</strong>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isBatchMarketInstructionsTransaction(tx.body)) {
|
||||
return <Details>{t('Batch market instruction')}</Details>;
|
||||
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 null;
|
||||
@@ -387,22 +396,22 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
|
||||
type VegaTxToastContentProps = { tx: VegaStoredTxState };
|
||||
|
||||
const VegaTxRequestedToastContent = ({ tx }: VegaTxToastContentProps) => (
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Action required')}</h3>
|
||||
<>
|
||||
<ToastHeading>{t('Action required')}</ToastHeading>
|
||||
<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 (
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Awaiting confirmation')}</h3>
|
||||
<>
|
||||
<ToastHeading>{t('Awaiting confirmation')}</ToastHeading>
|
||||
<p>{t('Please wait for your transaction to be confirmed')}</p>
|
||||
{tx.txHash && (
|
||||
<p className="break-all">
|
||||
@@ -415,7 +424,7 @@ const VegaTxPendingToastContentProps = ({ tx }: VegaTxToastContentProps) => {
|
||||
</p>
|
||||
)}
|
||||
<VegaTransactionDetails tx={tx} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -426,9 +435,10 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
})
|
||||
);
|
||||
const explorerLink = useLinks(DApp.Explorer);
|
||||
|
||||
if (isWithdrawTransaction(tx.body)) {
|
||||
const completeWithdrawalButton = tx.withdrawal && (
|
||||
<div className="mt-[10px]">
|
||||
<p className="mt-1">
|
||||
<Button
|
||||
data-testid="toast-complete-withdrawal"
|
||||
size="xs"
|
||||
@@ -441,11 +451,11 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
>
|
||||
{t('Complete withdrawal')}
|
||||
</Button>
|
||||
</div>
|
||||
</p>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Funds unlocked')}</h3>
|
||||
<>
|
||||
<ToastHeading>{t('Funds unlocked')}</ToastHeading>
|
||||
<p>{t('Your funds have been unlocked for withdrawal')}</p>
|
||||
{tx.txHash && (
|
||||
<p className="break-all">
|
||||
@@ -459,13 +469,68 @@ 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 (
|
||||
<div>
|
||||
<h3 className="font-bold">{t('Confirmed')}</h3>
|
||||
<>
|
||||
<ToastHeading>{t('Confirmed')}</ToastHeading>
|
||||
<p>{t('Your transaction has been confirmed ')}</p>
|
||||
{tx.txHash && (
|
||||
<p className="break-all">
|
||||
@@ -478,7 +543,7 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
</p>
|
||||
)}
|
||||
<VegaTransactionDetails tx={tx} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -501,7 +566,10 @@ const VegaTxErrorToastContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
walletNoConnectionCodes.includes(tx.error.code);
|
||||
if (orderRejection) {
|
||||
label = t('Order rejected');
|
||||
errorMessage = orderRejection;
|
||||
errorMessage = t(
|
||||
'Your order has been rejected because: %s',
|
||||
orderRejection
|
||||
);
|
||||
}
|
||||
if (walletError) {
|
||||
label = t('Wallet disconnected');
|
||||
@@ -509,60 +577,87 @@ const VegaTxErrorToastContent = ({ tx }: VegaTxToastContentProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3 className="font-bold">{label}</h3>
|
||||
<p>{errorMessage}</p>
|
||||
<>
|
||||
<ToastHeading>{label}</ToastHeading>
|
||||
<p className="first-letter:uppercase">{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 vegaTransactions = useVegaTransactionStore((state) =>
|
||||
state.transactions.filter((transaction) => transaction?.dialogOpen)
|
||||
);
|
||||
const dismissVegaTransaction = useVegaTransactionStore(
|
||||
(state) => state.dismiss
|
||||
);
|
||||
const [setToast, removeToast] = useToasts((store) => [
|
||||
store.setToast,
|
||||
store.remove,
|
||||
]);
|
||||
|
||||
const fromVegaTransaction = useCallback(
|
||||
(tx: VegaStoredTxState): Toast => {
|
||||
let content: ToastContent;
|
||||
if (tx.status === VegaTxStatus.Requested) {
|
||||
content = <VegaTxRequestedToastContent tx={tx} />;
|
||||
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);
|
||||
}
|
||||
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,
|
||||
};
|
||||
removeToast(`vega-${tx.id}`);
|
||||
},
|
||||
[dismissVegaTransaction]
|
||||
[deleteTx, dismissTx, removeToast]
|
||||
);
|
||||
|
||||
const toasts = useMemo(() => {
|
||||
return [
|
||||
...compact(vegaTransactions)
|
||||
.filter((tx) => isTransactionTypeSupported(tx))
|
||||
.map(fromVegaTransaction),
|
||||
];
|
||||
}, [fromVegaTransaction, vegaTransactions]);
|
||||
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} />;
|
||||
}
|
||||
|
||||
return toasts;
|
||||
// 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)));
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -33,6 +33,8 @@ import ToastsManager from './toasts-manager';
|
||||
import { HashRouter, useLocation, useSearchParams } from 'react-router-dom';
|
||||
import { Connectors } from '../lib/vega-connectors';
|
||||
import { ViewingBanner } from '../components/viewing-banner';
|
||||
import { Banner } from '../components/banner';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const DEFAULT_TITLE = t('Welcome to Vega trading!');
|
||||
|
||||
@@ -70,6 +72,11 @@ function AppBody({ Component }: AppProps) {
|
||||
const location = useLocation();
|
||||
const { VEGA_ENV } = useEnvironment();
|
||||
|
||||
const gridClasses = classNames(
|
||||
'h-full relative z-0 grid',
|
||||
'grid-rows-[repeat(3,min-content),1fr,min-content]'
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="h-full dark:bg-black dark:text-white">
|
||||
<Head>
|
||||
@@ -80,20 +87,21 @@ function AppBody({ Component }: AppProps) {
|
||||
<VegaWalletProvider>
|
||||
<AppLoader>
|
||||
<Web3Provider>
|
||||
<div className="h-full relative z-0 grid grid-rows-[min-content,min-content,1fr,min-content]">
|
||||
<div className={gridClasses}>
|
||||
<Navbar
|
||||
navbarTheme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'}
|
||||
/>
|
||||
<Banner />
|
||||
<ViewingBanner />
|
||||
<main data-testid={location.pathname}>
|
||||
<Component />
|
||||
</main>
|
||||
<Footer />
|
||||
<DialogsContainer />
|
||||
<ToastsManager />
|
||||
<TransactionsHandler />
|
||||
<MaybeConnectEagerly />
|
||||
</div>
|
||||
<DialogsContainer />
|
||||
<ToastsManager />
|
||||
<TransactionsHandler />
|
||||
<MaybeConnectEagerly />
|
||||
</Web3Provider>
|
||||
</AppLoader>
|
||||
</VegaWalletProvider>
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function Document() {
|
||||
<script src="/assets/env-config.js" type="text/javascript" />
|
||||
) : null}
|
||||
</Head>
|
||||
<body>
|
||||
<body className="font-alpha liga-0-calt-0">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { CreateWithdrawalDialog } from '@vegaprotocol/withdraws';
|
||||
import { DepositDialog } from '@vegaprotocol/deposits';
|
||||
import { Web3ConnectUncontrolledDialog } from '@vegaprotocol/web3';
|
||||
import { WelcomeDialog } from '../components/welcome-dialog';
|
||||
import { TransferDialog } from '@vegaprotocol/accounts';
|
||||
|
||||
const DialogsContainer = () => {
|
||||
const { isOpen, id, trigger, setOpen } = useAssetDetailsDialogStore();
|
||||
@@ -25,6 +26,7 @@ const DialogsContainer = () => {
|
||||
<DepositDialog />
|
||||
<Web3ConnectUncontrolledDialog />
|
||||
<CreateWithdrawalDialog />
|
||||
<TransferDialog />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,35 +1,16 @@
|
||||
import { ToastsContainer } from '@vegaprotocol/ui-toolkit';
|
||||
import { useMemo } from 'react';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
import { ToastsContainer, useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { useUpdateNetworkParametersToasts } from '@vegaprotocol/governance';
|
||||
|
||||
import { useVegaTransactionToasts } from '../lib/hooks/use-vega-transaction-toasts';
|
||||
import { useEthereumTransactionToasts } from '../lib/hooks/use-ethereum-transaction-toasts';
|
||||
import { useEthereumWithdrawApprovalsToasts } from '../lib/hooks/use-ethereum-withdraw-approval-toasts';
|
||||
|
||||
export const ToastsManager = () => {
|
||||
const updateNetworkParametersToasts = useUpdateNetworkParametersToasts();
|
||||
const vegaTransactionToasts = useVegaTransactionToasts();
|
||||
const ethTransactionToasts = useEthereumTransactionToasts();
|
||||
const withdrawApprovalToasts = useEthereumWithdrawApprovalsToasts();
|
||||
|
||||
const toasts = useMemo(() => {
|
||||
return sortBy(
|
||||
[
|
||||
...vegaTransactionToasts,
|
||||
...ethTransactionToasts,
|
||||
...withdrawApprovalToasts,
|
||||
...updateNetworkParametersToasts,
|
||||
],
|
||||
['createdBy']
|
||||
);
|
||||
}, [
|
||||
vegaTransactionToasts,
|
||||
ethTransactionToasts,
|
||||
withdrawApprovalToasts,
|
||||
updateNetworkParametersToasts,
|
||||
]);
|
||||
useUpdateNetworkParametersToasts();
|
||||
useVegaTransactionToasts();
|
||||
useEthereumTransactionToasts();
|
||||
useEthereumWithdrawApprovalsToasts();
|
||||
|
||||
const toasts = useToasts((store) => store.toasts);
|
||||
return <ToastsContainer order="desc" toasts={toasts} />;
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ interface GlobalStore {
|
||||
marketId: string | null;
|
||||
update: (store: Partial<Omit<GlobalStore, 'update'>>) => void;
|
||||
shouldDisplayWelcomeDialog: boolean;
|
||||
shouldDisplayAnnouncementBanner: boolean;
|
||||
}
|
||||
|
||||
interface PageTitleStore {
|
||||
@@ -18,6 +19,7 @@ export const useGlobalStore = create<GlobalStore>((set) => ({
|
||||
networkSwitcherDialog: false,
|
||||
marketId: LocalStorage.getItem('marketId') || null,
|
||||
shouldDisplayWelcomeDialog: false,
|
||||
shouldDisplayAnnouncementBanner: true,
|
||||
update: (newState) => {
|
||||
set(
|
||||
produce((state: GlobalStore) => {
|
||||
|
||||
@@ -7,3 +7,4 @@ export * from './breakdown-table';
|
||||
export * from './use-account-balance';
|
||||
export * from './get-settlement-account';
|
||||
export * from './use-market-account-balance';
|
||||
export * from './transfer-dialog';
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import {
|
||||
addDecimal,
|
||||
NetworkParams,
|
||||
t,
|
||||
truncateByChars,
|
||||
useDataProvider,
|
||||
useNetworkParam,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type { Transfer } from '@vegaprotocol/wallet';
|
||||
import { useVegaTransactionStore, useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { accountsDataProvider } from './accounts-data-provider';
|
||||
import { TransferForm } from './transfer-form';
|
||||
import { useTransferDialog } from './transfer-dialog';
|
||||
import { Lozenge } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export const TransferContainer = () => {
|
||||
const { pubKey, pubKeys } = useVegaWallet();
|
||||
const open = useTransferDialog((store) => store.open);
|
||||
const { param } = useNetworkParam(NetworkParams.transfer_fee_factor);
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: accountsDataProvider,
|
||||
variables: { partyId: pubKey },
|
||||
skip: !pubKey,
|
||||
});
|
||||
const create = useVegaTransactionStore((store) => store.create);
|
||||
|
||||
const transfer = useCallback(
|
||||
(transfer: Transfer) => {
|
||||
create({ transfer });
|
||||
open(false);
|
||||
},
|
||||
[create, open]
|
||||
);
|
||||
|
||||
const assets = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data
|
||||
.filter(
|
||||
(account) => account.type === Schema.AccountType.ACCOUNT_TYPE_GENERAL
|
||||
)
|
||||
.map((account) => ({
|
||||
id: account.asset.id,
|
||||
symbol: account.asset.symbol,
|
||||
name: account.asset.name,
|
||||
decimals: account.asset.decimals,
|
||||
balance: addDecimal(account.balance, account.asset.decimals),
|
||||
}));
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className="text-sm mb-4">
|
||||
{t('Transfer funds to another Vega key from')}{' '}
|
||||
<Lozenge className="font-mono">{truncateByChars(pubKey || '')}</Lozenge>{' '}
|
||||
{t('If you are at all unsure, stop and seek advice.')}
|
||||
</p>
|
||||
<TransferForm
|
||||
pubKey={pubKey}
|
||||
pubKeys={pubKeys ? pubKeys?.map((pk) => pk.publicKey) : null}
|
||||
assets={assets}
|
||||
feeFactor={param}
|
||||
submitTransfer={transfer}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { Dialog } from '@vegaprotocol/ui-toolkit';
|
||||
import { create } from 'zustand';
|
||||
import { TransferContainer } from './transfer-container';
|
||||
|
||||
interface State {
|
||||
isOpen: boolean;
|
||||
}
|
||||
|
||||
interface Actions {
|
||||
open: (open?: boolean) => void;
|
||||
}
|
||||
|
||||
export const useTransferDialog = create<State & Actions>((set) => ({
|
||||
isOpen: false,
|
||||
open: (open = true) => {
|
||||
set(() => ({ isOpen: open }));
|
||||
},
|
||||
}));
|
||||
|
||||
export const TransferDialog = () => {
|
||||
const { isOpen, open } = useTransferDialog();
|
||||
return (
|
||||
<Dialog title={t('Transfer')} open={isOpen} onChange={open} size="small">
|
||||
<TransferContainer />
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,177 @@
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { AddressField, TransferFee, TransferForm } from './transfer-form';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
import { formatNumber, removeDecimal } from '@vegaprotocol/react-helpers';
|
||||
|
||||
describe('TransferForm', () => {
|
||||
const submit = () => fireEvent.submit(screen.getByTestId('transfer-form'));
|
||||
const amount = '100';
|
||||
const pubKey =
|
||||
'70d14a321e02e71992fd115563df765000ccc4775cbe71a0e2f9ff5a3b9dc680';
|
||||
const asset = {
|
||||
id: 'asset-0',
|
||||
symbol: 'ASSET 0',
|
||||
name: 'Asset 0',
|
||||
decimals: 2,
|
||||
balance: '1000',
|
||||
};
|
||||
const props = {
|
||||
pubKey,
|
||||
pubKeys: [
|
||||
pubKey,
|
||||
'a4b6e3de5d7ef4e31ae1b090be49d1a2ef7bcefff60cccf7658a0d4922651cce',
|
||||
],
|
||||
assets: [asset],
|
||||
feeFactor: '0.001',
|
||||
submitTransfer: jest.fn(),
|
||||
};
|
||||
|
||||
it('validates fields and submits', async () => {
|
||||
render(<TransferForm {...props} />);
|
||||
|
||||
// check current pubkey not shown
|
||||
const keySelect: HTMLSelectElement = screen.getByLabelText('Vega key');
|
||||
expect(keySelect.children).toHaveLength(2);
|
||||
expect(Array.from(keySelect.options).map((o) => o.value)).toEqual([
|
||||
'',
|
||||
props.pubKeys[1],
|
||||
]);
|
||||
|
||||
submit();
|
||||
expect(await screen.findAllByText('Required')).toHaveLength(3);
|
||||
|
||||
// Select a pubkey
|
||||
fireEvent.change(screen.getByLabelText('Vega key'), {
|
||||
target: { value: props.pubKeys[1] },
|
||||
});
|
||||
|
||||
// Select asset
|
||||
fireEvent.change(
|
||||
// Bypass RichSelect and target hidden native select
|
||||
// eslint-disable-next-line
|
||||
document.querySelector('select[name="asset"]')!,
|
||||
{ target: { value: asset.id } }
|
||||
);
|
||||
|
||||
// assert rich select as updated
|
||||
expect(await screen.findByTestId('select-asset')).toHaveTextContent(
|
||||
asset.name
|
||||
);
|
||||
expect(screen.getByTestId('asset-balance')).toHaveTextContent(
|
||||
formatNumber(asset.balance, asset.decimals)
|
||||
);
|
||||
|
||||
// Test amount validation
|
||||
fireEvent.change(screen.getByLabelText('Amount'), {
|
||||
target: { value: '0.00000001' },
|
||||
});
|
||||
expect(
|
||||
await screen.findByText('Value is below minimum')
|
||||
).toBeInTheDocument();
|
||||
|
||||
fireEvent.change(screen.getByLabelText('Amount'), {
|
||||
target: { value: '9999999' },
|
||||
});
|
||||
expect(
|
||||
await screen.findByText(/cannot transfer more/i)
|
||||
).toBeInTheDocument();
|
||||
|
||||
// set valid amount
|
||||
fireEvent.change(screen.getByLabelText('Amount'), {
|
||||
target: { value: amount },
|
||||
});
|
||||
expect(screen.getByTestId('transfer-fee')).toHaveTextContent(
|
||||
new BigNumber(props.feeFactor).times(amount).toFixed()
|
||||
);
|
||||
|
||||
submit();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(props.submitTransfer).toHaveBeenCalledTimes(1);
|
||||
expect(props.submitTransfer).toHaveBeenCalledWith({
|
||||
fromAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
toAccountType: AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
to: props.pubKeys[1],
|
||||
asset: asset.id,
|
||||
amount: removeDecimal(amount, asset.decimals),
|
||||
oneOff: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('validates a manually entered address', async () => {
|
||||
render(<TransferForm {...props} />);
|
||||
submit();
|
||||
expect(await screen.findAllByText('Required')).toHaveLength(3);
|
||||
const toggle = screen.getByText('Enter manually');
|
||||
fireEvent.click(toggle);
|
||||
// has switched to input
|
||||
expect(toggle).toHaveTextContent('Select from wallet');
|
||||
expect(screen.getByLabelText('Vega key')).toHaveAttribute('type', 'text');
|
||||
fireEvent.change(screen.getByLabelText('Vega key'), {
|
||||
target: { value: 'invalid-address' },
|
||||
});
|
||||
await waitFor(() => {
|
||||
const errors = screen.getAllByTestId('input-error-text');
|
||||
expect(errors[0]).toHaveTextContent('Invalid Vega key');
|
||||
});
|
||||
|
||||
// same pubkey
|
||||
fireEvent.change(screen.getByLabelText('Vega key'), {
|
||||
target: { value: pubKey },
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
const errors = screen.getAllByTestId('input-error-text');
|
||||
expect(errors[0]).toHaveTextContent('Vega key is the same');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AddressField', () => {
|
||||
const props = {
|
||||
pubKeys: ['pubkey-1', 'pubkey-2'],
|
||||
select: <div>select</div>,
|
||||
input: <div>input</div>,
|
||||
onChange: jest.fn(),
|
||||
};
|
||||
|
||||
it('toggles content and calls onChange', async () => {
|
||||
const mockOnChange = jest.fn();
|
||||
render(<AddressField {...props} onChange={mockOnChange} />);
|
||||
|
||||
// select should be shown as multiple pubkeys provided
|
||||
expect(screen.getByText('select')).toBeInTheDocument();
|
||||
expect(screen.queryByText('input')).not.toBeInTheDocument();
|
||||
fireEvent.click(screen.getByText('Enter manually'));
|
||||
expect(screen.queryByText('select')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('input')).toBeInTheDocument();
|
||||
expect(mockOnChange).toHaveBeenCalledTimes(1);
|
||||
fireEvent.click(screen.getByText('Select from wallet'));
|
||||
expect(screen.getByText('select')).toBeInTheDocument();
|
||||
expect(screen.queryByText('input')).not.toBeInTheDocument();
|
||||
expect(mockOnChange).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('Does not provide select option if there is only a single key', () => {
|
||||
render(<AddressField {...props} pubKeys={['single-pubKey']} />);
|
||||
expect(screen.getByText('input')).toBeInTheDocument();
|
||||
expect(screen.queryByText('Select from wallet')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('TransferFee', () => {
|
||||
const props = {
|
||||
amount: '200',
|
||||
feeFactor: '0.001',
|
||||
};
|
||||
it('calculates and renders the transfer fee', () => {
|
||||
render(<TransferFee {...props} />);
|
||||
|
||||
const expected = new BigNumber(props.amount)
|
||||
.times(props.feeFactor)
|
||||
.toFixed();
|
||||
expect(screen.getByTestId('transfer-fee')).toHaveTextContent(expected);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,296 @@
|
||||
import {
|
||||
t,
|
||||
minSafe,
|
||||
maxSafe,
|
||||
required,
|
||||
vegaPublicKey,
|
||||
addDecimal,
|
||||
formatNumber,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
Button,
|
||||
FormGroup,
|
||||
Input,
|
||||
InputError,
|
||||
Option,
|
||||
RichSelect,
|
||||
Select,
|
||||
Tooltip,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import type { Transfer } from '@vegaprotocol/wallet';
|
||||
import { normalizeTransfer } from '@vegaprotocol/wallet';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
|
||||
interface FormFields {
|
||||
toAddress: string;
|
||||
asset: string;
|
||||
amount: string;
|
||||
}
|
||||
|
||||
interface TransferFormProps {
|
||||
pubKey: string | null;
|
||||
pubKeys: string[] | null;
|
||||
assets: Array<{
|
||||
id: string;
|
||||
symbol: string;
|
||||
name: string;
|
||||
decimals: number;
|
||||
balance: string;
|
||||
}>;
|
||||
feeFactor: string | null;
|
||||
submitTransfer: (transfer: Transfer) => void;
|
||||
}
|
||||
|
||||
export const TransferForm = ({
|
||||
pubKey,
|
||||
pubKeys,
|
||||
assets,
|
||||
feeFactor,
|
||||
submitTransfer,
|
||||
}: TransferFormProps) => {
|
||||
const {
|
||||
control,
|
||||
register,
|
||||
watch,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm<FormFields>();
|
||||
|
||||
const amount = watch('amount');
|
||||
const assetId = watch('asset');
|
||||
|
||||
const asset = useMemo(() => {
|
||||
return assets.find((a) => a.id === assetId);
|
||||
}, [assets, assetId]);
|
||||
|
||||
const onSubmit = useCallback(
|
||||
(fields: FormFields) => {
|
||||
if (!asset) {
|
||||
throw new Error('Submitted transfer with no asset selected');
|
||||
}
|
||||
const transfer = normalizeTransfer(fields.toAddress, fields.amount, {
|
||||
id: asset.id,
|
||||
decimals: asset.decimals,
|
||||
});
|
||||
submitTransfer(transfer);
|
||||
},
|
||||
[asset, submitTransfer]
|
||||
);
|
||||
|
||||
const min = useMemo(() => {
|
||||
// Min viable amount given asset decimals EG for WEI 0.000000000000000001
|
||||
const minViableAmount = asset
|
||||
? new BigNumber(addDecimal('1', asset.decimals))
|
||||
: new BigNumber(0);
|
||||
return minViableAmount;
|
||||
}, [asset]);
|
||||
|
||||
const max = useMemo(() => {
|
||||
const maxAmount = asset ? new BigNumber(asset.balance) : new BigNumber(0);
|
||||
return maxAmount;
|
||||
}, [asset]);
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="text-sm"
|
||||
data-testid="transfer-form"
|
||||
>
|
||||
<FormGroup label="Vega key" labelFor="to-address">
|
||||
<AddressField
|
||||
pubKeys={pubKeys}
|
||||
onChange={() => setValue('toAddress', '')}
|
||||
select={
|
||||
<Select {...register('toAddress')} id="to-address" defaultValue="">
|
||||
<option value="" disabled={true}>
|
||||
{t('Please select')}
|
||||
</option>
|
||||
{pubKeys?.length &&
|
||||
pubKeys
|
||||
.filter((pk) => pk !== pubKey) // remove currently selected pubkey
|
||||
.map((pk) => (
|
||||
<option key={pk} value={pk}>
|
||||
{pk}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
}
|
||||
input={
|
||||
<Input
|
||||
// eslint-disable-next-line jsx-a11y/no-autofocus
|
||||
autoFocus={true} // focus input immediately after is shown
|
||||
id="to-address"
|
||||
type="text"
|
||||
{...register('toAddress', {
|
||||
validate: {
|
||||
required,
|
||||
vegaPublicKey,
|
||||
sameKey: (value) => {
|
||||
if (value === pubKey) {
|
||||
return t('Vega key is the same as current key');
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
})}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{errors.toAddress?.message && (
|
||||
<InputError forInput="to-address">
|
||||
{errors.toAddress.message}
|
||||
</InputError>
|
||||
)}
|
||||
</FormGroup>
|
||||
<FormGroup label="Asset" labelFor="asset">
|
||||
<Controller
|
||||
control={control}
|
||||
name="asset"
|
||||
rules={{
|
||||
validate: {
|
||||
required,
|
||||
},
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<RichSelect
|
||||
data-testid="select-asset"
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value);
|
||||
}}
|
||||
placeholder={t('Please select')}
|
||||
value={field.value}
|
||||
>
|
||||
{assets.map((a) => (
|
||||
<Option key={a.id} value={a.id}>
|
||||
<div className="text-left" data-testid={`asset-${a.id}`}>
|
||||
<div>{a.name}</div>
|
||||
<div className="text-xs">
|
||||
<span className="font-mono" data-testid="asset-balance">
|
||||
{formatNumber(a.balance, a.decimals)}
|
||||
</span>{' '}
|
||||
<span>{a.symbol}</span>
|
||||
</div>
|
||||
</div>
|
||||
</Option>
|
||||
))}
|
||||
</RichSelect>
|
||||
)}
|
||||
/>
|
||||
{errors.asset?.message && (
|
||||
<InputError forInput="asset">{errors.asset.message}</InputError>
|
||||
)}
|
||||
</FormGroup>
|
||||
<FormGroup label="Amount" labelFor="amount">
|
||||
<Input
|
||||
id="amount"
|
||||
autoComplete="off"
|
||||
appendElement={
|
||||
asset && <span className="text-xs">{asset.symbol}</span>
|
||||
}
|
||||
{...register('amount', {
|
||||
validate: {
|
||||
required,
|
||||
minSafe: (value) => minSafe(new BigNumber(min))(value),
|
||||
maxSafe: (v) => {
|
||||
const value = new BigNumber(v);
|
||||
if (value.isGreaterThan(max)) {
|
||||
return t(
|
||||
'You cannot transfer more than your available collateral'
|
||||
);
|
||||
}
|
||||
return maxSafe(max)(v);
|
||||
},
|
||||
},
|
||||
})}
|
||||
/>
|
||||
{errors.amount?.message && (
|
||||
<InputError forInput="amount">{errors.amount.message}</InputError>
|
||||
)}
|
||||
</FormGroup>
|
||||
<TransferFee amount={amount} feeFactor={feeFactor} />
|
||||
<Button type="submit" variant="primary" fill={true}>
|
||||
{t('Confirm transfer')}
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export const TransferFee = ({
|
||||
amount,
|
||||
feeFactor,
|
||||
}: {
|
||||
amount: string;
|
||||
feeFactor: string | null;
|
||||
}) => {
|
||||
if (!feeFactor || !amount) return null;
|
||||
|
||||
// using toFixed without an argument will always return a
|
||||
// number in normal notation without rounding, formatting functions
|
||||
// arent working in a way which won't round the decimal places
|
||||
const value = new BigNumber(amount).times(feeFactor).toFixed();
|
||||
|
||||
return (
|
||||
<div className="mb-4 flex justify-between items-center gap-4 flex-wrap">
|
||||
<div>
|
||||
<Tooltip
|
||||
description={t(
|
||||
`The transfer fee is set by the network parameter transfer.fee.factor, currently set to ${feeFactor}`
|
||||
)}
|
||||
>
|
||||
<div>{t('Transfer fee')}</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div
|
||||
data-testid="transfer-fee"
|
||||
className="text-neutral-500 dark:text-neutral-300"
|
||||
>
|
||||
{value}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface AddressInputProps {
|
||||
pubKeys: string[] | null;
|
||||
select: ReactNode;
|
||||
input: ReactNode;
|
||||
onChange: () => void;
|
||||
}
|
||||
|
||||
export const AddressField = ({
|
||||
pubKeys,
|
||||
select,
|
||||
input,
|
||||
onChange,
|
||||
}: AddressInputProps) => {
|
||||
const [isInput, setIsInput] = useState(() => {
|
||||
if (pubKeys && pubKeys.length <= 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{isInput ? input : select}
|
||||
{pubKeys && pubKeys.length > 1 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setIsInput((curr) => !curr);
|
||||
onChange();
|
||||
}}
|
||||
className="ml-auto text-sm absolute top-0 right-0 underline"
|
||||
>
|
||||
{isInput ? t('Select from wallet') : t('Enter manually')}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'pennant/dist/style.css';
|
||||
|
||||
import {
|
||||
Chart,
|
||||
ChartType,
|
||||
@@ -168,6 +167,11 @@ export const CandlesChartContainer = ({
|
||||
chartType: chartType,
|
||||
overlays: overlays,
|
||||
studies: studies,
|
||||
notEnoughDataText: (
|
||||
<span className="text-xs text-center text-neutral-800 dark:text-neutral-200">
|
||||
{t('No data')}
|
||||
</span>
|
||||
),
|
||||
}}
|
||||
interval={interval}
|
||||
theme={theme}
|
||||
|
||||
@@ -20,14 +20,19 @@ export const AssetProposalNotification = ({
|
||||
const proposalLink = tokenLink(
|
||||
TOKEN_PROPOSAL.replace(':id', proposal.id || '')
|
||||
);
|
||||
const message = (
|
||||
<>
|
||||
{t('Changes have been proposed for this asset.')}{' '}
|
||||
<ExternalLink href={proposalLink}>{t('View proposal')}</ExternalLink>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<Notification
|
||||
intent={Intent.Warning}
|
||||
message={t('Changes have been proposed for this asset')}
|
||||
message={message}
|
||||
testId="asset-proposal-notification"
|
||||
>
|
||||
<ExternalLink href={proposalLink}>{t('View proposal')}</ExternalLink>
|
||||
</Notification>
|
||||
className="mb-2"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,14 +20,23 @@ export const MarketProposalNotification = ({
|
||||
const proposalLink = tokenLink(
|
||||
TOKEN_PROPOSAL.replace(':id', proposal.id || '')
|
||||
);
|
||||
const message = (
|
||||
<div className="flex flex-col text-sm">
|
||||
{t('Changes have been proposed for this market.')}{' '}
|
||||
<ExternalLink href={proposalLink} className="w-fit">
|
||||
{t('View proposal')}
|
||||
</ExternalLink>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<Notification
|
||||
intent={Intent.Warning}
|
||||
message={t('Changes have been proposed for this market')}
|
||||
testId="market-proposal-notification"
|
||||
>
|
||||
<ExternalLink href={proposalLink}>{t('View proposal')}</ExternalLink>
|
||||
</Notification>
|
||||
<div className="border-l border-default pl-1 pr-1 pb-1 min-w-min whitespace-nowrap">
|
||||
<Notification
|
||||
intent={Intent.Warning}
|
||||
message={message}
|
||||
testId="market-proposal-notification"
|
||||
className="px-2 py-1"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { UpdateNetworkParameter } from '@vegaprotocol/types';
|
||||
import { ProposalStateMapping } from '@vegaprotocol/types';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
import type { Toast } from '@vegaprotocol/ui-toolkit';
|
||||
import { ToastHeading } from '@vegaprotocol/ui-toolkit';
|
||||
import { useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { ExternalLink, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import compact from 'lodash/compact';
|
||||
@@ -28,7 +29,7 @@ const UpdateNetworkParameterToastContent = ({
|
||||
const enactment = Date.parse(proposal.terms.enactmentDatetime);
|
||||
return (
|
||||
<div>
|
||||
<h3 className="font-bold">{title}</h3>
|
||||
<ToastHeading>{title}</ToastHeading>
|
||||
<p className="italic">
|
||||
'
|
||||
{t(
|
||||
@@ -52,9 +53,8 @@ const UpdateNetworkParameterToastContent = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const useUpdateNetworkParametersToasts = (): Toast[] => {
|
||||
const { proposalToasts, setToast, remove } = useToasts((store) => ({
|
||||
proposalToasts: store.toasts,
|
||||
export const useUpdateNetworkParametersToasts = () => {
|
||||
const { setToast, remove } = useToasts((store) => ({
|
||||
setToast: store.setToast,
|
||||
remove: store.remove,
|
||||
}));
|
||||
@@ -66,7 +66,9 @@ export const useUpdateNetworkParametersToasts = (): Toast[] => {
|
||||
id: `update-network-param-proposal-${proposal.id}`,
|
||||
intent: Intent.Warning,
|
||||
content: <UpdateNetworkParameterToastContent proposal={proposal} />,
|
||||
onClose: () => remove(id),
|
||||
onClose: () => {
|
||||
remove(id);
|
||||
},
|
||||
closeAfter: CLOSE_AFTER,
|
||||
};
|
||||
},
|
||||
@@ -96,6 +98,4 @@ export const useUpdateNetworkParametersToasts = (): Toast[] => {
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return proposalToasts;
|
||||
};
|
||||
|
||||
+14
-21
@@ -1,6 +1,6 @@
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { ProposalState } from '@vegaprotocol/types';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useUpdateNetworkParametersToasts } from './use-update-network-paramaters-toasts';
|
||||
@@ -9,8 +9,8 @@ import type {
|
||||
OnUpdateNetworkParametersSubscription,
|
||||
} from './__generated__/Proposal';
|
||||
import { OnUpdateNetworkParametersDocument } from './__generated__/Proposal';
|
||||
import waitForNextTick from 'flush-promises';
|
||||
import { useToasts } from '@vegaprotocol/ui-toolkit';
|
||||
import { waitFor } from '@testing-library/react';
|
||||
|
||||
const render = (mocks?: MockedResponse[]) => {
|
||||
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||
@@ -92,11 +92,10 @@ const mockedEvent: MockedResponse<OnUpdateNetworkParametersSubscription> = {
|
||||
},
|
||||
};
|
||||
|
||||
const INITIAL = useToasts.getState();
|
||||
|
||||
const clear = () => {
|
||||
const { result: clearer } = renderHook(() =>
|
||||
useToasts((store) => store.removeAll)
|
||||
);
|
||||
act(() => clearer.current());
|
||||
useToasts.setState(INITIAL);
|
||||
};
|
||||
|
||||
describe('useUpdateNetworkParametersToasts', () => {
|
||||
@@ -104,29 +103,23 @@ describe('useUpdateNetworkParametersToasts', () => {
|
||||
afterAll(clear);
|
||||
|
||||
it('returns toast for update network parameters bus event', async () => {
|
||||
const { waitForNextUpdate, result } = render([mockedEvent]);
|
||||
await act(async () => {
|
||||
waitForNextUpdate();
|
||||
await waitForNextTick();
|
||||
render([mockedEvent]);
|
||||
await waitFor(() => {
|
||||
expect(useToasts.getState().count).toBe(1);
|
||||
});
|
||||
expect(result.current.length).toBe(1);
|
||||
});
|
||||
|
||||
it('does not return toast for empty event', async () => {
|
||||
const { waitForNextUpdate, result } = render([mockedEmptyEvent]);
|
||||
await act(async () => {
|
||||
waitForNextUpdate();
|
||||
await waitForNextTick();
|
||||
render([mockedEmptyEvent]);
|
||||
await waitFor(() => {
|
||||
expect(useToasts.getState().count).toBe(0);
|
||||
});
|
||||
expect(result.current.length).toBe(0);
|
||||
});
|
||||
|
||||
it('does not return toast for wrong event', async () => {
|
||||
const { waitForNextUpdate, result } = render([mockedWrongEvent]);
|
||||
await act(async () => {
|
||||
waitForNextUpdate();
|
||||
await waitForNextTick();
|
||||
render([mockedWrongEvent]);
|
||||
await waitFor(() => {
|
||||
expect(useToasts.getState().count).toBe(0);
|
||||
});
|
||||
expect(result.current.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
addDecimal,
|
||||
getNumberFormat,
|
||||
useThemeSwitcher,
|
||||
t,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { marketDepthProvider } from './market-depth-provider';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
@@ -207,6 +208,11 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
|
||||
theme={theme}
|
||||
volumeFormat={volumeFormat}
|
||||
priceFormat={priceFormat}
|
||||
notEnoughDataText={
|
||||
<span className="text-xs text-center text-neutral-800 dark:text-neutral-200">
|
||||
{t('No data')}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</AsyncRenderer>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export * from './order-data-provider';
|
||||
export * from './order-feedback';
|
||||
export * from './order-list';
|
||||
export * from './order-list-manager';
|
||||
export * from './order-list-container';
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './order-feedback';
|
||||
@@ -1,83 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { VegaTxStatus } from '@vegaprotocol/wallet';
|
||||
import type { OrderEventFieldsFragment } from '../../order-hooks';
|
||||
import { generateOrder } from '../mocks/generate-orders';
|
||||
import type { OrderFeedbackProps } from './order-feedback';
|
||||
import { OrderFeedback } from './order-feedback';
|
||||
|
||||
jest.mock('@vegaprotocol/environment', () => ({
|
||||
useEnvironment: () => ({
|
||||
VEGA_EXPLORER_URL: 'https://test.explorer.vega.network',
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('OrderFeedback', () => {
|
||||
let props: OrderFeedbackProps;
|
||||
|
||||
beforeEach(() => {
|
||||
props = {
|
||||
transaction: {
|
||||
dialogOpen: false,
|
||||
status: VegaTxStatus.Complete,
|
||||
error: null,
|
||||
txHash: 'tx-hash',
|
||||
signature: null,
|
||||
},
|
||||
order: null,
|
||||
};
|
||||
});
|
||||
|
||||
it('renders null if no order provided', () => {
|
||||
const { container } = render(<OrderFeedback {...props} />);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('renders error reason', () => {
|
||||
const orderFields = {
|
||||
status: Schema.OrderStatus.STATUS_REJECTED,
|
||||
rejectionReason: Schema.OrderRejectionReason.ORDER_ERROR_AMEND_FAILURE,
|
||||
};
|
||||
const order = generateOrder(orderFields) as OrderEventFieldsFragment;
|
||||
render(<OrderFeedback {...props} order={order} />);
|
||||
expect(screen.getByTestId('error-reason')).toHaveTextContent(
|
||||
`${Schema.OrderRejectionReasonMapping[orderFields.rejectionReason]}`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render order details when order is placed successfully', () => {
|
||||
const order = generateOrder({
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
price: '100',
|
||||
size: '200',
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
market: {
|
||||
decimalPlaces: 2,
|
||||
positionDecimalPlaces: 0,
|
||||
},
|
||||
}) as OrderEventFieldsFragment;
|
||||
render(<OrderFeedback {...props} order={order} />);
|
||||
expect(screen.getByTestId('order-confirmed')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('tx-block-explorer')).toHaveTextContent(
|
||||
// eslint-disable-next-line
|
||||
props.transaction.txHash!
|
||||
);
|
||||
expect(screen.getByTestId('tx-block-explorer')).toHaveTextContent(
|
||||
// eslint-disable-next-line
|
||||
props.transaction.txHash!
|
||||
);
|
||||
expect(screen.getByText('Market').nextElementSibling).toHaveTextContent(
|
||||
// eslint-disable-next-line
|
||||
order.market!.tradableInstrument.instrument.name
|
||||
);
|
||||
expect(screen.getByText('Status').nextElementSibling).toHaveTextContent(
|
||||
Schema.OrderStatusMapping[order.status]
|
||||
);
|
||||
expect(screen.getByText('Price').nextElementSibling).toHaveTextContent(
|
||||
'1.00'
|
||||
);
|
||||
expect(screen.getByText('Size').nextElementSibling).toHaveTextContent(
|
||||
`+200`
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,94 +0,0 @@
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import type { OrderEventFieldsFragment } from '../../order-hooks/__generated__/OrderEvent';
|
||||
import { addDecimalsFormatNumber, Size, t } from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { VegaTxState } from '@vegaprotocol/wallet';
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export interface OrderFeedbackProps {
|
||||
transaction: VegaTxState;
|
||||
order: OrderEventFieldsFragment | null;
|
||||
}
|
||||
|
||||
export const OrderFeedback = ({ transaction, order }: OrderFeedbackProps) => {
|
||||
const { VEGA_EXPLORER_URL } = useEnvironment();
|
||||
const labelClass = 'font-bold text-black dark:text-white capitalize';
|
||||
if (!order) return null;
|
||||
|
||||
const orderRejectionReason = getRejectionReason(order);
|
||||
|
||||
return (
|
||||
<div data-testid="order-confirmed" className="w-full">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8">
|
||||
{order.market && (
|
||||
<div>
|
||||
<p className={labelClass}>{t(`Market`)}</p>
|
||||
<p>{t(`${order.market.tradableInstrument.instrument.name}`)}</p>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<p className={labelClass}>{t(`Status`)}</p>
|
||||
<p>{t(`${Schema.OrderStatusMapping[order.status]}`)}</p>
|
||||
</div>
|
||||
{order.type === Schema.OrderType.TYPE_LIMIT && order.market && (
|
||||
<div>
|
||||
<p className={labelClass}>{t(`Price`)}</p>
|
||||
<p>
|
||||
{addDecimalsFormatNumber(order.price, order.market.decimalPlaces)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<p className={labelClass}>{t(`Size`)}</p>
|
||||
<p>
|
||||
<Size
|
||||
value={order.size}
|
||||
side={order.side}
|
||||
positionDecimalPlaces={order.market.positionDecimalPlaces}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-8 mb-8">
|
||||
{transaction.txHash && (
|
||||
<div>
|
||||
<p className={labelClass}>{t('Transaction')}</p>
|
||||
<Link
|
||||
style={{ wordBreak: 'break-word' }}
|
||||
data-testid="tx-block-explorer"
|
||||
href={`${VEGA_EXPLORER_URL}/txs/0x${transaction.txHash}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{transaction.txHash}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{orderRejectionReason && (
|
||||
<div>
|
||||
<p className={labelClass}>{t(`Reason`)}</p>
|
||||
<p data-testid="error-reason">{t(orderRejectionReason)}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const getRejectionReason = (
|
||||
order: OrderEventFieldsFragment
|
||||
): string | null => {
|
||||
switch (order.status) {
|
||||
case Schema.OrderStatus.STATUS_STOPPED:
|
||||
return t(
|
||||
`Your ${
|
||||
Schema.OrderTimeInForceMapping[order.timeInForce]
|
||||
} order was not filled and it has been stopped`
|
||||
);
|
||||
default:
|
||||
return order.rejectionReason
|
||||
? t(Schema.OrderRejectionReasonMapping[order.rejectionReason])
|
||||
: null;
|
||||
}
|
||||
};
|
||||
@@ -19,56 +19,58 @@ const generateJsx = () => {
|
||||
);
|
||||
};
|
||||
|
||||
it('Renders a loading state while awaiting orders', async () => {
|
||||
jest.spyOn(useDataProviderHook, 'useDataProvider').mockReturnValue({
|
||||
data: [],
|
||||
loading: true,
|
||||
error: undefined,
|
||||
flush: jest.fn(),
|
||||
reload: jest.fn(),
|
||||
load: jest.fn(),
|
||||
totalCount: 0,
|
||||
describe('OrderListManager', () => {
|
||||
it('should render a loading state while awaiting orders', async () => {
|
||||
jest.spyOn(useDataProviderHook, 'useDataProvider').mockReturnValue({
|
||||
data: [],
|
||||
loading: true,
|
||||
error: undefined,
|
||||
flush: jest.fn(),
|
||||
reload: jest.fn(),
|
||||
load: jest.fn(),
|
||||
totalCount: 0,
|
||||
});
|
||||
await act(async () => {
|
||||
render(generateJsx());
|
||||
});
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
});
|
||||
await act(async () => {
|
||||
render(generateJsx());
|
||||
});
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders an error state', async () => {
|
||||
const errorMsg = 'Oops! An Error';
|
||||
jest.spyOn(useDataProviderHook, 'useDataProvider').mockReturnValue({
|
||||
data: [],
|
||||
loading: false,
|
||||
error: new Error(errorMsg),
|
||||
flush: jest.fn(),
|
||||
reload: jest.fn(),
|
||||
load: jest.fn(),
|
||||
totalCount: undefined,
|
||||
it('should render an error state', async () => {
|
||||
const errorMsg = 'Oops! An Error';
|
||||
jest.spyOn(useDataProviderHook, 'useDataProvider').mockReturnValue({
|
||||
data: null,
|
||||
loading: false,
|
||||
error: new Error(errorMsg),
|
||||
flush: jest.fn(),
|
||||
reload: jest.fn(),
|
||||
load: jest.fn(),
|
||||
totalCount: undefined,
|
||||
});
|
||||
await act(async () => {
|
||||
render(generateJsx());
|
||||
});
|
||||
expect(
|
||||
screen.getByText(`Something went wrong: ${errorMsg}`)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
await act(async () => {
|
||||
render(generateJsx());
|
||||
});
|
||||
expect(
|
||||
screen.getByText(`Something went wrong: ${errorMsg}`)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Renders the order list if orders provided', async () => {
|
||||
// @ts-ignore Orderlist is read only but we need to override with the forwardref to
|
||||
// avoid warnings about padding refs
|
||||
orderListMock.OrderListTable = forwardRef(() => <div>OrderList</div>);
|
||||
jest.spyOn(useDataProviderHook, 'useDataProvider').mockReturnValue({
|
||||
data: [{ id: '1' } as OrderFieldsFragment],
|
||||
loading: false,
|
||||
error: undefined,
|
||||
flush: jest.fn(),
|
||||
reload: jest.fn(),
|
||||
load: jest.fn(),
|
||||
totalCount: undefined,
|
||||
it('should render the order list if orders provided', async () => {
|
||||
// @ts-ignore OrderList is read only but we need to override with the forwardRef to
|
||||
// avoid warnings about padding refs
|
||||
orderListMock.OrderListTable = forwardRef(() => <div>OrderList</div>);
|
||||
jest.spyOn(useDataProviderHook, 'useDataProvider').mockReturnValue({
|
||||
data: [{ id: '1' } as OrderFieldsFragment],
|
||||
loading: false,
|
||||
error: undefined,
|
||||
flush: jest.fn(),
|
||||
reload: jest.fn(),
|
||||
load: jest.fn(),
|
||||
totalCount: undefined,
|
||||
});
|
||||
await act(async () => {
|
||||
render(generateJsx());
|
||||
});
|
||||
expect(await screen.findByText('OrderList')).toBeInTheDocument();
|
||||
});
|
||||
await act(async () => {
|
||||
render(generateJsx());
|
||||
});
|
||||
expect(await screen.findByText('OrderList')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
} from '@vegaprotocol/wallet';
|
||||
import type { VegaTxState, TransactionResult } from '@vegaprotocol/wallet';
|
||||
import { OrderEditDialog } from '../order-list/order-edit-dialog';
|
||||
import type { OrderEventFieldsFragment } from '../../order-hooks';
|
||||
import type { OrderSubFieldsFragment } from '../../order-hooks';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { Order } from '../order-data-provider';
|
||||
|
||||
@@ -238,7 +238,7 @@ export const getCancelDialogIntent = ({
|
||||
cancelledOrder,
|
||||
transactionResult,
|
||||
}: {
|
||||
cancelledOrder: OrderEventFieldsFragment | null;
|
||||
cancelledOrder: OrderSubFieldsFragment | null;
|
||||
transactionResult?: TransactionResult;
|
||||
}): Intent | undefined => {
|
||||
if (cancelledOrder) {
|
||||
@@ -260,7 +260,7 @@ export const getCancelDialogTitle = ({
|
||||
cancelledOrder,
|
||||
transactionResult,
|
||||
}: {
|
||||
cancelledOrder: OrderEventFieldsFragment | null;
|
||||
cancelledOrder: OrderSubFieldsFragment | null;
|
||||
transactionResult?: TransactionResult;
|
||||
}): string | undefined => {
|
||||
if (cancelledOrder) {
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
fragment OrderEventFields on Order {
|
||||
type
|
||||
id
|
||||
status
|
||||
rejectionReason
|
||||
createdAt
|
||||
size
|
||||
price
|
||||
timeInForce
|
||||
expiresAt
|
||||
side
|
||||
market {
|
||||
id
|
||||
decimalPlaces
|
||||
positionDecimalPlaces
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subscription OrderEvent($partyId: ID!) {
|
||||
busEvents(partyId: $partyId, batchSize: 0, types: [Order]) {
|
||||
type
|
||||
event {
|
||||
... on Order {
|
||||
...OrderEventFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
fragment OrderSubFields on OrderUpdate {
|
||||
type
|
||||
id
|
||||
status
|
||||
rejectionReason
|
||||
createdAt
|
||||
size
|
||||
price
|
||||
timeInForce
|
||||
expiresAt
|
||||
side
|
||||
marketId
|
||||
}
|
||||
|
||||
subscription OrderSub($partyId: ID!) {
|
||||
orders(partyId: $partyId) {
|
||||
...OrderSubFields
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type OrderEventFieldsFragment = { __typename?: 'Order', type?: Types.OrderType | null, id: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, createdAt: any, size: string, price: string, timeInForce: Types.OrderTimeInForce, expiresAt?: any | null, side: Types.Side, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } } } };
|
||||
|
||||
export type OrderEventSubscriptionVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type OrderEventSubscription = { __typename?: 'Subscription', busEvents?: Array<{ __typename?: 'BusEvent', type: Types.BusEventType, event: { __typename?: 'AccountEvent' } | { __typename?: 'Asset' } | { __typename?: 'AuctionEvent' } | { __typename?: 'Deposit' } | { __typename?: 'LiquidityProvision' } | { __typename?: 'LossSocialization' } | { __typename?: 'MarginLevels' } | { __typename?: 'Market' } | { __typename?: 'MarketData' } | { __typename?: 'MarketEvent' } | { __typename?: 'MarketTick' } | { __typename?: 'NodeSignature' } | { __typename?: 'OracleSpec' } | { __typename?: 'Order', type?: Types.OrderType | null, id: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, createdAt: any, size: string, price: string, timeInForce: Types.OrderTimeInForce, expiresAt?: any | null, side: Types.Side, market: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } } } } | { __typename?: 'Party' } | { __typename?: 'PositionResolution' } | { __typename?: 'Proposal' } | { __typename?: 'RiskFactor' } | { __typename?: 'SettleDistressed' } | { __typename?: 'SettlePosition' } | { __typename?: 'TimeUpdate' } | { __typename?: 'Trade' } | { __typename?: 'TransactionResult' } | { __typename?: 'TransferResponses' } | { __typename?: 'Vote' } | { __typename?: 'Withdrawal' } }> | null };
|
||||
|
||||
export const OrderEventFieldsFragmentDoc = gql`
|
||||
fragment OrderEventFields on Order {
|
||||
type
|
||||
id
|
||||
status
|
||||
rejectionReason
|
||||
createdAt
|
||||
size
|
||||
price
|
||||
timeInForce
|
||||
expiresAt
|
||||
side
|
||||
market {
|
||||
id
|
||||
decimalPlaces
|
||||
positionDecimalPlaces
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const OrderEventDocument = gql`
|
||||
subscription OrderEvent($partyId: ID!) {
|
||||
busEvents(partyId: $partyId, batchSize: 0, types: [Order]) {
|
||||
type
|
||||
event {
|
||||
... on Order {
|
||||
...OrderEventFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${OrderEventFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useOrderEventSubscription__
|
||||
*
|
||||
* To run a query within a React component, call `useOrderEventSubscription` and pass it any options that fit your needs.
|
||||
* When your component renders, `useOrderEventSubscription` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useOrderEventSubscription({
|
||||
* variables: {
|
||||
* partyId: // value for 'partyId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useOrderEventSubscription(baseOptions: Apollo.SubscriptionHookOptions<OrderEventSubscription, OrderEventSubscriptionVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useSubscription<OrderEventSubscription, OrderEventSubscriptionVariables>(OrderEventDocument, options);
|
||||
}
|
||||
export type OrderEventSubscriptionHookResult = ReturnType<typeof useOrderEventSubscription>;
|
||||
export type OrderEventSubscriptionResult = Apollo.SubscriptionResult<OrderEventSubscription>;
|
||||
@@ -0,0 +1,59 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type OrderSubFieldsFragment = { __typename?: 'OrderUpdate', type?: Types.OrderType | null, id: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, createdAt: any, size: string, price: string, timeInForce: Types.OrderTimeInForce, expiresAt?: any | null, side: Types.Side, marketId: string };
|
||||
|
||||
export type OrderSubSubscriptionVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type OrderSubSubscription = { __typename?: 'Subscription', orders?: Array<{ __typename?: 'OrderUpdate', type?: Types.OrderType | null, id: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, createdAt: any, size: string, price: string, timeInForce: Types.OrderTimeInForce, expiresAt?: any | null, side: Types.Side, marketId: string }> | null };
|
||||
|
||||
export const OrderSubFieldsFragmentDoc = gql`
|
||||
fragment OrderSubFields on OrderUpdate {
|
||||
type
|
||||
id
|
||||
status
|
||||
rejectionReason
|
||||
createdAt
|
||||
size
|
||||
price
|
||||
timeInForce
|
||||
expiresAt
|
||||
side
|
||||
marketId
|
||||
}
|
||||
`;
|
||||
export const OrderSubDocument = gql`
|
||||
subscription OrderSub($partyId: ID!) {
|
||||
orders(partyId: $partyId) {
|
||||
...OrderSubFields
|
||||
}
|
||||
}
|
||||
${OrderSubFieldsFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useOrderSubSubscription__
|
||||
*
|
||||
* To run a query within a React component, call `useOrderSubSubscription` and pass it any options that fit your needs.
|
||||
* When your component renders, `useOrderSubSubscription` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useOrderSubSubscription({
|
||||
* variables: {
|
||||
* partyId: // value for 'partyId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useOrderSubSubscription(baseOptions: Apollo.SubscriptionHookOptions<OrderSubSubscription, OrderSubSubscriptionVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useSubscription<OrderSubSubscription, OrderSubSubscriptionVariables>(OrderSubDocument, options);
|
||||
}
|
||||
export type OrderSubSubscriptionHookResult = ReturnType<typeof useOrderSubSubscription>;
|
||||
export type OrderSubSubscriptionResult = Apollo.SubscriptionResult<OrderSubSubscription>;
|
||||
@@ -1,7 +1,7 @@
|
||||
export * from './__generated__/OrderEvent';
|
||||
export * from './__generated__/OrdersSubscription';
|
||||
export * from './use-has-active-order';
|
||||
export * from './use-order-cancel';
|
||||
export * from './use-order-submit';
|
||||
export * from './use-order-edit';
|
||||
export * from './use-order-event';
|
||||
export * from './use-order-update';
|
||||
export * from './use-persisted-order';
|
||||
|
||||
@@ -5,8 +5,8 @@ import type { ReactNode } from 'react';
|
||||
import { VegaTxStatus, VegaWalletContext } from '@vegaprotocol/wallet';
|
||||
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||
import { useOrderCancel } from './use-order-cancel';
|
||||
import type { OrderEventSubscription } from './';
|
||||
import { OrderEventDocument } from './';
|
||||
import type { OrderSubSubscription } from './';
|
||||
import { OrderSubDocument } from './';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
const defaultWalletContext = {
|
||||
@@ -21,89 +21,57 @@ const defaultWalletContext = {
|
||||
};
|
||||
|
||||
function setup(context?: Partial<VegaWalletContextShape>) {
|
||||
const mocks: MockedResponse<OrderEventSubscription> = {
|
||||
const mocks: MockedResponse<OrderSubSubscription> = {
|
||||
request: {
|
||||
query: OrderEventDocument,
|
||||
query: OrderSubDocument,
|
||||
variables: {
|
||||
partyId: context?.pubKey || '',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
busEvents: [
|
||||
orders: [
|
||||
{
|
||||
type: Schema.BusEventType.Order,
|
||||
event: {
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
market: {
|
||||
id: 'market-id',
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 0,
|
||||
tradableInstrument: {
|
||||
__typename: 'TradableInstrument',
|
||||
instrument: {
|
||||
name: 'UNIDAI Monthly (30 Jun 2022)',
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
},
|
||||
__typename: 'Market',
|
||||
},
|
||||
__typename: 'Order',
|
||||
},
|
||||
__typename: 'BusEvent',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
marketId: 'market-id',
|
||||
__typename: 'OrderUpdate',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
const filterMocks: MockedResponse<OrderEventSubscription> = {
|
||||
const filterMocks: MockedResponse<OrderSubSubscription> = {
|
||||
request: {
|
||||
query: OrderEventDocument,
|
||||
query: OrderSubDocument,
|
||||
variables: {
|
||||
partyId: context?.pubKey || '',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
busEvents: [
|
||||
orders: [
|
||||
{
|
||||
type: Schema.BusEventType.Order,
|
||||
event: {
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
market: {
|
||||
id: 'market-id',
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 0,
|
||||
tradableInstrument: {
|
||||
__typename: 'TradableInstrument',
|
||||
instrument: {
|
||||
name: 'UNIDAI Monthly (30 Jun 2022)',
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
},
|
||||
__typename: 'Market',
|
||||
},
|
||||
__typename: 'Order',
|
||||
},
|
||||
__typename: 'BusEvent',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
marketId: 'market-id',
|
||||
__typename: 'OrderUpdate',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -8,15 +8,15 @@ import type {
|
||||
OrderCancellationBody,
|
||||
TransactionResult,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import type { OrderEventFieldsFragment } from './';
|
||||
import type { OrderSubFieldsFragment } from './';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { useOrderEvent } from './use-order-event';
|
||||
import { useOrderUpdate } from './use-order-update';
|
||||
|
||||
export const useOrderCancel = () => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
|
||||
const [cancelledOrder, setCancelledOrder] =
|
||||
useState<OrderEventFieldsFragment | null>(null);
|
||||
useState<OrderSubFieldsFragment | null>(null);
|
||||
const [transactionResult, setTransactionResult] =
|
||||
useState<TransactionResult>();
|
||||
|
||||
@@ -28,7 +28,7 @@ export const useOrderCancel = () => {
|
||||
Dialog,
|
||||
} = useVegaTransaction();
|
||||
|
||||
const waitForOrderEvent = useOrderEvent(transaction);
|
||||
const waitForOrderUpdate = useOrderUpdate(transaction);
|
||||
const waitForTransactionResult = useTransactionResult();
|
||||
|
||||
const reset = useCallback(() => {
|
||||
@@ -49,7 +49,7 @@ export const useOrderCancel = () => {
|
||||
orderCancellation,
|
||||
});
|
||||
if (orderCancellation.orderId) {
|
||||
const cancelledOrder = await waitForOrderEvent(
|
||||
const cancelledOrder = await waitForOrderUpdate(
|
||||
orderCancellation.orderId,
|
||||
pubKey
|
||||
);
|
||||
@@ -69,7 +69,7 @@ export const useOrderCancel = () => {
|
||||
return;
|
||||
}
|
||||
},
|
||||
[pubKey, send, setComplete, waitForOrderEvent, waitForTransactionResult]
|
||||
[pubKey, send, setComplete, waitForOrderUpdate, waitForTransactionResult]
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -3,8 +3,8 @@ import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
|
||||
import { VegaTxStatus, VegaWalletContext } from '@vegaprotocol/wallet';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useOrderEdit } from './use-order-edit';
|
||||
import type { OrderEventSubscription } from './__generated__/OrderEvent';
|
||||
import { OrderEventDocument } from './__generated__/OrderEvent';
|
||||
import type { OrderSubSubscription } from './__generated__/OrdersSubscription';
|
||||
import { OrderSubDocument } from './__generated__/OrdersSubscription';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import type { Order } from '../components';
|
||||
@@ -23,89 +23,57 @@ const defaultWalletContext = {
|
||||
};
|
||||
|
||||
function setup(order: Order, context?: Partial<VegaWalletContextShape>) {
|
||||
const mocks: MockedResponse<OrderEventSubscription> = {
|
||||
const mocks: MockedResponse<OrderSubSubscription> = {
|
||||
request: {
|
||||
query: OrderEventDocument,
|
||||
query: OrderSubDocument,
|
||||
variables: {
|
||||
partyId: context?.pubKey || '',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
busEvents: [
|
||||
orders: [
|
||||
{
|
||||
type: Schema.BusEventType.Order,
|
||||
event: {
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
market: {
|
||||
id: 'market-id',
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 0,
|
||||
tradableInstrument: {
|
||||
__typename: 'TradableInstrument',
|
||||
instrument: {
|
||||
name: 'UNIDAI Monthly (30 Jun 2022)',
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
},
|
||||
__typename: 'Market',
|
||||
},
|
||||
__typename: 'Order',
|
||||
},
|
||||
__typename: 'BusEvent',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
marketId: 'market-id',
|
||||
__typename: 'OrderUpdate',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
const filterMocks: MockedResponse<OrderEventSubscription> = {
|
||||
const filterMocks: MockedResponse<OrderSubSubscription> = {
|
||||
request: {
|
||||
query: OrderEventDocument,
|
||||
query: OrderSubDocument,
|
||||
variables: {
|
||||
partyId: context?.pubKey || '',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
busEvents: [
|
||||
orders: [
|
||||
{
|
||||
type: Schema.BusEventType.Order,
|
||||
event: {
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
market: {
|
||||
id: 'market-id',
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 0,
|
||||
tradableInstrument: {
|
||||
__typename: 'TradableInstrument',
|
||||
instrument: {
|
||||
name: 'UNIDAI Monthly (30 Jun 2022)',
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
},
|
||||
__typename: 'Market',
|
||||
},
|
||||
__typename: 'Order',
|
||||
},
|
||||
__typename: 'BusEvent',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
marketId: 'market-id',
|
||||
__typename: 'OrderUpdate',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { removeDecimal, toNanoSeconds } from '@vegaprotocol/react-helpers';
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useVegaTransaction, useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import type { OrderEventFieldsFragment } from './';
|
||||
import type { OrderSubFieldsFragment } from './';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import type { Order } from '../components';
|
||||
import { useOrderEvent } from './use-order-event';
|
||||
import { useOrderUpdate } from './use-order-update';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
export interface EditOrderArgs {
|
||||
@@ -16,7 +16,7 @@ export const useOrderEdit = (order: Order | null) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
|
||||
const [updatedOrder, setUpdatedOrder] =
|
||||
useState<OrderEventFieldsFragment | null>(null);
|
||||
useState<OrderSubFieldsFragment | null>(null);
|
||||
|
||||
const {
|
||||
send,
|
||||
@@ -26,7 +26,7 @@ export const useOrderEdit = (order: Order | null) => {
|
||||
Dialog,
|
||||
} = useVegaTransaction();
|
||||
|
||||
const waitForOrderEvent = useOrderEvent(transaction);
|
||||
const waitForOrderUpdate = useOrderUpdate(transaction);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
resetTransaction();
|
||||
@@ -61,7 +61,7 @@ export const useOrderEdit = (order: Order | null) => {
|
||||
},
|
||||
});
|
||||
|
||||
const updatedOrder = await waitForOrderEvent(order.id, pubKey);
|
||||
const updatedOrder = await waitForOrderUpdate(order.id, pubKey);
|
||||
setUpdatedOrder(updatedOrder);
|
||||
setComplete();
|
||||
} catch (e) {
|
||||
@@ -69,7 +69,7 @@ export const useOrderEdit = (order: Order | null) => {
|
||||
return;
|
||||
}
|
||||
},
|
||||
[pubKey, send, order, setComplete, waitForOrderEvent]
|
||||
[pubKey, send, order, setComplete, waitForOrderUpdate]
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { OrderEventDocument } from './__generated__/OrderEvent';
|
||||
import type {
|
||||
OrderEventSubscription,
|
||||
OrderEventSubscriptionVariables,
|
||||
OrderEventFieldsFragment,
|
||||
} from './__generated__/OrderEvent';
|
||||
import type { Subscription } from 'zen-observable-ts';
|
||||
import type { VegaTxState } from '@vegaprotocol/wallet';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
type WaitFunc = (
|
||||
orderId: string,
|
||||
partyId: string
|
||||
) => Promise<OrderEventFieldsFragment>;
|
||||
|
||||
export const useOrderEvent = (transaction: VegaTxState) => {
|
||||
const client = useApolloClient();
|
||||
const subRef = useRef<Subscription | null>(null);
|
||||
|
||||
const waitForOrderEvent = useCallback<WaitFunc>(
|
||||
(id: string, partyId: string) => {
|
||||
return new Promise((resolve) => {
|
||||
subRef.current = client
|
||||
.subscribe<OrderEventSubscription, OrderEventSubscriptionVariables>({
|
||||
query: OrderEventDocument,
|
||||
variables: { partyId },
|
||||
})
|
||||
.subscribe(({ data }) => {
|
||||
if (!data?.busEvents?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No types available for the subscription result
|
||||
const matchingOrderEvent = data.busEvents.find((e) => {
|
||||
if (e.event.__typename !== Schema.BusEventType.Order) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return e.event.id === id;
|
||||
});
|
||||
|
||||
if (
|
||||
matchingOrderEvent &&
|
||||
matchingOrderEvent.event.__typename === Schema.BusEventType.Order
|
||||
) {
|
||||
resolve(matchingOrderEvent.event);
|
||||
subRef.current?.unsubscribe();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
[client]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!transaction.dialogOpen) {
|
||||
subRef.current?.unsubscribe();
|
||||
}
|
||||
|
||||
return () => {
|
||||
subRef.current?.unsubscribe();
|
||||
};
|
||||
}, [transaction.dialogOpen]);
|
||||
|
||||
return waitForOrderEvent;
|
||||
};
|
||||
@@ -5,8 +5,8 @@ import * as Schema from '@vegaprotocol/types';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { useOrderSubmit } from './use-order-submit';
|
||||
import type { OrderEventSubscription } from './';
|
||||
import { OrderEventDocument } from './';
|
||||
import type { OrderSubSubscription } from './';
|
||||
import { OrderSubDocument } from './';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
|
||||
@@ -48,89 +48,56 @@ const defaultWalletContext = {
|
||||
};
|
||||
|
||||
function setup(context?: Partial<VegaWalletContextShape>) {
|
||||
const mocks: MockedResponse<OrderEventSubscription> = {
|
||||
const mocks: MockedResponse<OrderSubSubscription> = {
|
||||
request: {
|
||||
query: OrderEventDocument,
|
||||
query: OrderSubDocument,
|
||||
variables: {
|
||||
partyId: context?.pubKey || '',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
busEvents: [
|
||||
orders: [
|
||||
{
|
||||
type: Schema.BusEventType.Order,
|
||||
event: {
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
market: {
|
||||
id: 'market-id',
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 0,
|
||||
tradableInstrument: {
|
||||
__typename: 'TradableInstrument',
|
||||
instrument: {
|
||||
name: 'UNIDAI Monthly (30 Jun 2022)',
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
},
|
||||
__typename: 'Market',
|
||||
},
|
||||
__typename: 'Order',
|
||||
},
|
||||
__typename: 'BusEvent',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
marketId: 'market-id',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
const filterMocks: MockedResponse<OrderEventSubscription> = {
|
||||
const filterMocks: MockedResponse<OrderSubSubscription> = {
|
||||
request: {
|
||||
query: OrderEventDocument,
|
||||
query: OrderSubDocument,
|
||||
variables: {
|
||||
partyId: context?.pubKey || '',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
busEvents: [
|
||||
orders: [
|
||||
{
|
||||
type: Schema.BusEventType.Order,
|
||||
event: {
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
market: {
|
||||
id: 'market-id',
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 0,
|
||||
tradableInstrument: {
|
||||
__typename: 'TradableInstrument',
|
||||
instrument: {
|
||||
name: 'UNIDAI Monthly (30 Jun 2022)',
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
},
|
||||
__typename: 'Market',
|
||||
},
|
||||
__typename: 'Order',
|
||||
},
|
||||
__typename: 'BusEvent',
|
||||
type: Schema.OrderType.TYPE_LIMIT,
|
||||
id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62',
|
||||
status: Schema.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
marketId: 'market-id',
|
||||
__typename: 'OrderUpdate',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { OrderEventFieldsFragment } from './__generated__/OrderEvent';
|
||||
import type { OrderSubFieldsFragment } from './__generated__/OrdersSubscription';
|
||||
import {
|
||||
useVegaWallet,
|
||||
useVegaTransaction,
|
||||
determineId,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { useOrderEvent } from './use-order-event';
|
||||
import { useOrderUpdate } from './use-order-update';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { Icon, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
@@ -96,10 +96,10 @@ export const useOrderSubmit = () => {
|
||||
Dialog,
|
||||
} = useVegaTransaction();
|
||||
|
||||
const waitForOrderEvent = useOrderEvent(transaction);
|
||||
const waitForOrderUpdate = useOrderUpdate(transaction);
|
||||
|
||||
const [finalizedOrder, setFinalizedOrder] =
|
||||
useState<OrderEventFieldsFragment | null>(null);
|
||||
useState<OrderSubFieldsFragment | null>(null);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
resetTransaction();
|
||||
@@ -120,7 +120,7 @@ export const useOrderSubmit = () => {
|
||||
if (res) {
|
||||
const orderId = determineId(res.signature);
|
||||
if (orderId) {
|
||||
const order = await waitForOrderEvent(orderId, pubKey);
|
||||
const order = await waitForOrderUpdate(orderId, pubKey);
|
||||
setFinalizedOrder(order);
|
||||
setComplete();
|
||||
}
|
||||
@@ -129,7 +129,7 @@ export const useOrderSubmit = () => {
|
||||
Sentry.captureException(e);
|
||||
}
|
||||
},
|
||||
[pubKey, send, setComplete, waitForOrderEvent]
|
||||
[pubKey, send, setComplete, waitForOrderUpdate]
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { OrderSubDocument } from './__generated__/OrdersSubscription';
|
||||
import type {
|
||||
OrderSubSubscription,
|
||||
OrderSubSubscriptionVariables,
|
||||
OrderSubFieldsFragment,
|
||||
} from './__generated__/OrdersSubscription';
|
||||
import type { Subscription } from 'zen-observable-ts';
|
||||
import type { VegaTxState } from '@vegaprotocol/wallet';
|
||||
|
||||
type WaitFunc = (
|
||||
orderId: string,
|
||||
partyId: string
|
||||
) => Promise<OrderSubFieldsFragment>;
|
||||
|
||||
export const useOrderUpdate = (transaction: VegaTxState) => {
|
||||
const client = useApolloClient();
|
||||
const subRef = useRef<Subscription | null>(null);
|
||||
|
||||
const waitForOrderUpdate = useCallback<WaitFunc>(
|
||||
(id: string, partyId: string) => {
|
||||
return new Promise((resolve) => {
|
||||
subRef.current = client
|
||||
.subscribe<OrderSubSubscription, OrderSubSubscriptionVariables>({
|
||||
query: OrderSubDocument,
|
||||
variables: { partyId },
|
||||
})
|
||||
.subscribe(({ data }) => {
|
||||
if (!data?.orders?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No types available for the subscription result
|
||||
const matchingOrder = data.orders.find((order) => {
|
||||
return order.id === id;
|
||||
});
|
||||
|
||||
if (matchingOrder) {
|
||||
resolve(matchingOrder);
|
||||
subRef.current?.unsubscribe();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
[client]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!transaction.dialogOpen) {
|
||||
subRef.current?.unsubscribe();
|
||||
}
|
||||
|
||||
return () => {
|
||||
subRef.current?.unsubscribe();
|
||||
};
|
||||
}, [transaction.dialogOpen]);
|
||||
|
||||
return waitForOrderUpdate;
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { OrderSubFieldsFragment } from './order-hooks';
|
||||
|
||||
// More detail in https://docs.vega.xyz/mainnet/graphql/enums/order-time-in-force
|
||||
export const timeInForceLabel = (tif: string) => {
|
||||
@@ -20,3 +21,20 @@ export const timeInForceLabel = (tif: string) => {
|
||||
return t(tif);
|
||||
}
|
||||
};
|
||||
|
||||
export const getRejectionReason = (
|
||||
order: OrderSubFieldsFragment
|
||||
): string | null => {
|
||||
switch (order.status) {
|
||||
case Schema.OrderStatus.STATUS_STOPPED:
|
||||
return t(
|
||||
`Your ${
|
||||
Schema.OrderTimeInForceMapping[order.timeInForce]
|
||||
} order was not filled and it has been stopped`
|
||||
);
|
||||
default:
|
||||
return order.rejectionReason
|
||||
? t(Schema.OrderRejectionReasonMapping[order.rejectionReason])
|
||||
: null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -335,7 +335,6 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
|
||||
? undefined
|
||||
: addDecimalsFormatNumber(data.realisedPNL, data.decimals);
|
||||
}}
|
||||
cellRenderer="PriceFlashCell"
|
||||
headerTooltip={t(
|
||||
'Profit or loss is realised whenever your position is reduced to zero and the margin is released back to your collateral balance. P&L excludes any fees paid.'
|
||||
)}
|
||||
@@ -360,7 +359,6 @@ export const PositionsTable = forwardRef<AgGridReact, Props>(
|
||||
? undefined
|
||||
: addDecimalsFormatNumber(data.unrealisedPNL, data.decimals)
|
||||
}
|
||||
cellRenderer="PriceFlashCell"
|
||||
headerTooltip={t(
|
||||
'Unrealised profit is the current profit on your open position. Margin is still allocated to your position.'
|
||||
)}
|
||||
|
||||
@@ -10,8 +10,8 @@ import { initialState } from '@vegaprotocol/wallet';
|
||||
import type { TransactionEventSubscription } from '@vegaprotocol/wallet';
|
||||
import { TransactionEventDocument } from '@vegaprotocol/wallet';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import type { OrderEventSubscription } from '@vegaprotocol/orders';
|
||||
import { OrderEventDocument } from '@vegaprotocol/orders';
|
||||
import type { OrderSubSubscription } from '@vegaprotocol/orders';
|
||||
import { OrderSubDocument } from '@vegaprotocol/orders';
|
||||
|
||||
const pubKey = 'test-pubkey';
|
||||
const defaultWalletContext = {
|
||||
@@ -52,45 +52,29 @@ function setup(context?: Partial<VegaWalletContextShape>) {
|
||||
},
|
||||
},
|
||||
};
|
||||
const mockOrderResult: MockedResponse<OrderEventSubscription> = {
|
||||
const mockOrderResult: MockedResponse<OrderSubSubscription> = {
|
||||
request: {
|
||||
query: OrderEventDocument,
|
||||
query: OrderSubDocument,
|
||||
variables: {
|
||||
partyId: context?.pubKey || '',
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
busEvents: [
|
||||
orders: [
|
||||
{
|
||||
type: Types.BusEventType.Order,
|
||||
event: {
|
||||
type: Types.OrderType.TYPE_LIMIT,
|
||||
id: '2fca514cebf9f465ae31ecb4c5721e3a6f5f260425ded887ca50ba15b81a5d50',
|
||||
status: Types.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Types.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Types.Side.SIDE_BUY,
|
||||
market: {
|
||||
id: 'market-id',
|
||||
decimalPlaces: 5,
|
||||
positionDecimalPlaces: 0,
|
||||
tradableInstrument: {
|
||||
__typename: 'TradableInstrument',
|
||||
instrument: {
|
||||
name: 'UNIDAI Monthly (30 Jun 2022)',
|
||||
__typename: 'Instrument',
|
||||
},
|
||||
},
|
||||
__typename: 'Market',
|
||||
},
|
||||
__typename: 'Order',
|
||||
},
|
||||
__typename: 'BusEvent',
|
||||
type: Types.OrderType.TYPE_LIMIT,
|
||||
id: '2fca514cebf9f465ae31ecb4c5721e3a6f5f260425ded887ca50ba15b81a5d50',
|
||||
status: Types.OrderStatus.STATUS_ACTIVE,
|
||||
rejectionReason: null,
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
price: '300000',
|
||||
timeInForce: Types.OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Types.Side.SIDE_BUY,
|
||||
marketId: 'market-id',
|
||||
__typename: 'OrderUpdate',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -5,8 +5,8 @@ import { useVegaWallet, useTransactionResult } from '@vegaprotocol/wallet';
|
||||
import { useVegaTransaction } from '@vegaprotocol/wallet';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { useOrderEvent } from '@vegaprotocol/orders';
|
||||
import type { OrderEventFieldsFragment } from '@vegaprotocol/orders';
|
||||
import { useOrderUpdate } from '@vegaprotocol/orders';
|
||||
import type { OrderSubFieldsFragment } from '@vegaprotocol/orders';
|
||||
|
||||
export interface ClosingOrder {
|
||||
marketId: string;
|
||||
@@ -21,11 +21,11 @@ export const useClosePosition = () => {
|
||||
const { send, transaction, setComplete, Dialog } = useVegaTransaction();
|
||||
const [closingOrder, setClosingOrder] = useState<ClosingOrder>();
|
||||
const [closingOrderResult, setClosingOrderResult] =
|
||||
useState<OrderEventFieldsFragment>();
|
||||
useState<OrderSubFieldsFragment>();
|
||||
const [transactionResult, setTransactionResult] =
|
||||
useState<TransactionResult>();
|
||||
const waitForTransactionResult = useTransactionResult();
|
||||
const waitForOrder = useOrderEvent(transaction);
|
||||
const waitForOrder = useOrderUpdate(transaction);
|
||||
|
||||
const submit = useCallback(
|
||||
async ({
|
||||
|
||||
@@ -2,6 +2,7 @@ import { renderHook, waitFor } from '@testing-library/react';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import type { NetworkParamsKey } from './use-network-params';
|
||||
import { toRealKey } from './use-network-params';
|
||||
import {
|
||||
NetworkParams,
|
||||
useNetworkParam,
|
||||
@@ -18,7 +19,7 @@ describe('useNetworkParam', () => {
|
||||
request: {
|
||||
query: NetworkParamDocument,
|
||||
variables: {
|
||||
key: arg,
|
||||
key: toRealKey(arg),
|
||||
},
|
||||
},
|
||||
result: {
|
||||
|
||||
@@ -104,10 +104,11 @@ export const NetworkParams = {
|
||||
market_liquidity_stakeToCcyVolume: 'market_liquidity_stakeToCcyVolume',
|
||||
market_liquidity_targetstake_triggering_ratio:
|
||||
'market_liquidity_targetstake_triggering_ratio',
|
||||
transfer_fee_factor: 'transfer_fee_factor',
|
||||
} as const;
|
||||
|
||||
type Params = typeof NetworkParams;
|
||||
export type NetworkParamsKey = Params[keyof Params];
|
||||
export type NetworkParamsKey = keyof Params;
|
||||
type Result = {
|
||||
[key in keyof Params]: string;
|
||||
};
|
||||
@@ -120,7 +121,7 @@ export const useNetworkParams = <T extends NetworkParamsKey[]>(params?: T) => {
|
||||
return compact(data.networkParametersConnection.edges)
|
||||
.map((p) => ({
|
||||
...p.node,
|
||||
key: p.node.key.split('.').join('_'),
|
||||
key: toInternalKey(p.node.key),
|
||||
}))
|
||||
.filter((p) => {
|
||||
if (params === undefined || params.length === 0) return true;
|
||||
@@ -143,7 +144,7 @@ export const useNetworkParams = <T extends NetworkParamsKey[]>(params?: T) => {
|
||||
export const useNetworkParam = (param: NetworkParamsKey) => {
|
||||
const { data, loading, error } = useNetworkParamQuery({
|
||||
variables: {
|
||||
key: param,
|
||||
key: toRealKey(param),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -153,3 +154,11 @@ export const useNetworkParam = (param: NetworkParamsKey) => {
|
||||
error,
|
||||
};
|
||||
};
|
||||
|
||||
export const toRealKey = (key: NetworkParamsKey) => {
|
||||
return key.split('_').join('.');
|
||||
};
|
||||
|
||||
export const toInternalKey = (key: string) => {
|
||||
return key.split('.').join('_');
|
||||
};
|
||||
|
||||
@@ -99,20 +99,20 @@ module.exports = {
|
||||
|
||||
// DARK
|
||||
dark: {
|
||||
400: '#161616',
|
||||
300: '#262626',
|
||||
100: '#161616',
|
||||
150: '#262626',
|
||||
200: '#404040',
|
||||
150: '#8B8B8B',
|
||||
100: '#C0C0C0',
|
||||
300: '#8B8B8B',
|
||||
400: '#C0C0C0',
|
||||
},
|
||||
|
||||
// LIGHT
|
||||
light: {
|
||||
400: '#F0F0F0',
|
||||
300: '#E9E9E9',
|
||||
100: '#F0F0F0',
|
||||
150: '#E9E9E9',
|
||||
200: '#D2D2D2',
|
||||
150: '#939393',
|
||||
100: '#626262',
|
||||
300: '#939393',
|
||||
400: '#626262',
|
||||
},
|
||||
},
|
||||
danger: '#FF077F',
|
||||
@@ -174,11 +174,16 @@ module.exports = {
|
||||
'60%': { transform: 'rotate( 0.0deg)' },
|
||||
'100%': { transform: 'rotate( 0.0deg)' },
|
||||
},
|
||||
progress: {
|
||||
from: { width: '0' },
|
||||
to: { width: '100%' },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
rotate: 'rotate 2s linear alternate infinite',
|
||||
'rotate-back': 'rotate 2s linear reverse infinite',
|
||||
wave: 'wave 2s linear infinite',
|
||||
progress: 'progress 5s cubic-bezier(.39,.58,.57,1) 1',
|
||||
},
|
||||
data: {
|
||||
selected: 'state~="checked"',
|
||||
|
||||
@@ -10,6 +10,9 @@ const vegaCustomClasses = plugin(function ({ addUtilities }) {
|
||||
'.liga-0-calt-0': {
|
||||
fontFeatureSettings: "'liga' 0, 'calt' 0",
|
||||
},
|
||||
'.liga': {
|
||||
fontFeatureSettings: "'liga'",
|
||||
},
|
||||
'.syntax-highlighter-wrapper .hljs': {
|
||||
fontSize: '1rem',
|
||||
fontFamily: "Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace",
|
||||
|
||||
Generated
-4
@@ -3894,10 +3894,6 @@ export type Statistics = {
|
||||
chainVersion: Scalars['String'];
|
||||
/** RFC3339Nano current time (real) */
|
||||
currentTime: Scalars['Timestamp'];
|
||||
/** Total number of events on the last block */
|
||||
eventCount: Scalars['String'];
|
||||
/** The number of events per second on the last block */
|
||||
eventsPerSecond: Scalars['String'];
|
||||
/** RFC3339Nano genesis time of the chain */
|
||||
genesisTime: Scalars['Timestamp'];
|
||||
/** Number of orders per seconds */
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Splash } from '../splash';
|
||||
import type { ReactNode } from 'react';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import * as Sentry from '@sentry/react';
|
||||
|
||||
interface AsyncRendererProps<T> {
|
||||
loading: boolean;
|
||||
@@ -26,13 +27,16 @@ export function AsyncRenderer<T = object>({
|
||||
render,
|
||||
}: AsyncRendererProps<T>) {
|
||||
if (error) {
|
||||
return (
|
||||
<Splash>
|
||||
{errorMessage
|
||||
? errorMessage
|
||||
: t(`Something went wrong: ${error.message}`)}
|
||||
</Splash>
|
||||
);
|
||||
Sentry.captureException(`Error rendering data: ${error.message}`);
|
||||
if (!data) {
|
||||
return (
|
||||
<Splash>
|
||||
{errorMessage
|
||||
? errorMessage
|
||||
: t(`Something went wrong: ${error.message}`)}
|
||||
</Splash>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
|
||||
@@ -151,7 +151,7 @@ export const DropdownMenuSeparator = forwardRef<
|
||||
{...separatorProps}
|
||||
ref={forwardedRef}
|
||||
className={classNames(
|
||||
'h-px my-1 mx-2 bg-neutral-700 dark:bg-black',
|
||||
'h-px my-1 mx-2 bg-neutral-400 dark:bg-neutral-300',
|
||||
className
|
||||
)}
|
||||
/>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user