diff --git a/apps/explorer/.env b/apps/explorer/.env index 3533b45b9..5e2cdf10c 100644 --- a/apps/explorer/.env +++ b/apps/explorer/.env @@ -6,6 +6,7 @@ NX_VEGA_NETWORKS={\"MAINNET"\:\"https://explorer.vega.xyz"\,\"TESTNET\":\"https: NX_VEGA_ENV=STAGNET3 NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz +NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_BLOCK_EXPLORER= # App flags diff --git a/apps/explorer/.env.capsule b/apps/explorer/.env.capsule index 671cb92cc..12a95171c 100644 --- a/apps/explorer/.env.capsule +++ b/apps/explorer/.env.capsule @@ -5,6 +5,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket NX_VEGA_NETWORKS={\"MAINNET"\:\"https://explorer.vega.xyz"\,\"TESTNET\":\"https://explorer.fairground.wtf\"} NX_VEGA_ENV=CUSTOM NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions +NX_ETHERSCAN_URL=https://sepolia.etherscan.io # App flags NX_EXPLORER_ASSETS=1 diff --git a/apps/explorer/.env.devnet b/apps/explorer/.env.devnet index 551fcfdaf..de899a888 100644 --- a/apps/explorer/.env.devnet +++ b/apps/explorer/.env.devnet @@ -7,3 +7,4 @@ NX_VEGA_NETWORKS={\"MAINNET"\:\"https://explorer.vega.xyz"\,\"TESTNET\":\"https: NX_VEGA_ENV=DEVNET NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest +NX_ETHERSCAN_URL=https://sepolia.etherscan.io \ No newline at end of file diff --git a/apps/explorer/.env.mainnet b/apps/explorer/.env.mainnet index 5440658ed..dc4a636cd 100644 --- a/apps/explorer/.env.mainnet +++ b/apps/explorer/.env.mainnet @@ -7,3 +7,4 @@ NX_VEGA_NETWORKS={\"MAINNET"\:\"https://explorer.vega.xyz"\,\"TESTNET\":\"https: NX_VEGA_ENV=MAINNET NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest/ +NX_ETHERSCAN_URL=https://etherscan.io diff --git a/apps/explorer/.env.sandbox b/apps/explorer/.env.sandbox index 361575744..c9fafd228 100644 --- a/apps/explorer/.env.sandbox +++ b/apps/explorer/.env.sandbox @@ -8,3 +8,4 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_VEGA_NETWORKS={\"MAINNET"\:\"https://explorer.vega.xyz"\,\"TESTNET\":\"https://explorer.fairground.wtf\"} NX_TENDERMINT_URL=https://tm.n01.sandbox.vega.xyz NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.sandbox.vega.xyz/websocket +NX_ETHERSCAN_URL=https://sepolia.etherscan.io diff --git a/apps/explorer/.env.stagnet1 b/apps/explorer/.env.stagnet1 index be6b48499..de57494c2 100644 --- a/apps/explorer/.env.stagnet1 +++ b/apps/explorer/.env.stagnet1 @@ -10,3 +10,4 @@ NX_VEGA_WALLET_URL=http://localhost:1789 NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.xyz NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket NX_BLOCK_EXPLORER=https://be.stagnet1.vega.xyz/rest +NX_ETHERSCAN_URL=https://sepolia.etherscan.io diff --git a/apps/explorer/.env.stagnet3 b/apps/explorer/.env.stagnet3 index d5fcebed7..3afd50d64 100644 --- a/apps/explorer/.env.stagnet3 +++ b/apps/explorer/.env.stagnet3 @@ -7,3 +7,4 @@ NX_VEGA_NETWORKS={\"MAINNET"\:\"https://explorer.vega.xyz"\,\"TESTNET\":\"https: NX_VEGA_ENV=STAGNET3 NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest +NX_ETHERSCAN_URL=https://be.stagnet3.vega.xyz/rest \ No newline at end of file diff --git a/apps/explorer/.env.testnet b/apps/explorer/.env.testnet index 6afef2cb8..457ea79b6 100644 --- a/apps/explorer/.env.testnet +++ b/apps/explorer/.env.testnet @@ -9,4 +9,5 @@ NX_VEGA_ENV=TESTNET NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz -NX_VEGA_NETWORKS={} \ No newline at end of file +NX_VEGA_NETWORKS={} +NX_ETHERSCAN_URL=https://sepolia.etherscan.io diff --git a/apps/explorer/.env.vegacapsule b/apps/explorer/.env.vegacapsule index ebc25363c..b59f49214 100644 --- a/apps/explorer/.env.vegacapsule +++ b/apps/explorer/.env.vegacapsule @@ -5,3 +5,4 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26607/websocket NX_VEGA_ENV=CUSTOM NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions NX_BLOCK_EXPLORER= +NX_ETHERSCAN_URL=https://sepolia.etherscan.io diff --git a/apps/explorer/project.json b/apps/explorer/project.json index 9bd14a156..26f15df38 100644 --- a/apps/explorer/project.json +++ b/apps/explorer/project.json @@ -66,6 +66,14 @@ "passWithNoTests": true } }, + "generate-types": { + "executor": "@nrwl/workspace:run-commands", + "options": { + "commands": [ + "npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.62.1/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types" + ] + } + }, "build-netlify": { "executor": "@nrwl/workspace:run-commands", "options": { diff --git a/apps/explorer/src/app/components/links/asset-link/asset-link.tsx b/apps/explorer/src/app/components/links/asset-link/asset-link.tsx index 65b0e2229..271bf1a23 100644 --- a/apps/explorer/src/app/components/links/asset-link/asset-link.tsx +++ b/apps/explorer/src/app/components/links/asset-link/asset-link.tsx @@ -26,7 +26,7 @@ const AssetLink = ({ id, ...props }: AssetLinkProps) => { } return ( - + {label} ); diff --git a/apps/explorer/src/app/components/links/eth-explorer-link/eth-explorer-link.tsx b/apps/explorer/src/app/components/links/eth-explorer-link/eth-explorer-link.tsx new file mode 100644 index 000000000..24a81db89 --- /dev/null +++ b/apps/explorer/src/app/components/links/eth-explorer-link/eth-explorer-link.tsx @@ -0,0 +1,33 @@ +import React from 'react'; + +import { DATA_SOURCES } from '../../../config'; + +export enum EthExplorerLinkTypes { + block = 'block', + address = 'address', + tx = 'tx', +} + +export type EthExplorerLinkProps = Partial & { + id: string; + type: EthExplorerLinkTypes; +}; + +export const EthExplorerLink = ({ + id, + type, + ...props +}: EthExplorerLinkProps) => { + const link = `${DATA_SOURCES.ethExplorerUrl}/${type}/${id}`; + return ( + + {id} + + ); +}; diff --git a/apps/explorer/src/app/components/links/market-link/market-link.tsx b/apps/explorer/src/app/components/links/market-link/market-link.tsx index e5789a6ca..578d3a56c 100644 --- a/apps/explorer/src/app/components/links/market-link/market-link.tsx +++ b/apps/explorer/src/app/components/links/market-link/market-link.tsx @@ -19,7 +19,7 @@ const MarketLink = ({ id, ...props }: MarketLinkProps) => { variables: { id }, }); - let label: string = id; + let label = id; if (data?.market?.tradableInstrument.instrument.name) { label = data.market.tradableInstrument.instrument.name; diff --git a/apps/explorer/src/app/components/time/index.tsx b/apps/explorer/src/app/components/time/index.tsx new file mode 100644 index 000000000..10e9bc3af --- /dev/null +++ b/apps/explorer/src/app/components/time/index.tsx @@ -0,0 +1,14 @@ +import { t } from '@vegaprotocol/react-helpers'; + +interface TimeProps { + date: string | null | undefined; +} + +export const Time = ({ date }: TimeProps) => { + if (!date) { + return <>{t('Date unknown')}; + } + const timeFormatted = new Date(date).toLocaleString(); + + return {timeFormatted}; +}; diff --git a/apps/explorer/src/app/components/txs/details/__generated___/node-vote.ts b/apps/explorer/src/app/components/txs/details/__generated___/node-vote.ts new file mode 100644 index 000000000..a986b8cdf --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/__generated___/node-vote.ts @@ -0,0 +1,75 @@ +import { Schema as Types } from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type ExplorerNodeVoteQueryVariables = Types.Exact<{ + id: Types.Scalars['ID']; +}>; + + +export type ExplorerNodeVoteQuery = { __typename?: 'Query', withdrawal?: { __typename?: 'Withdrawal', id: string, status: Types.WithdrawalStatus, createdTimestamp: string, withdrawnTimestamp?: string | null, txHash?: string | null, asset: { __typename?: 'Asset', id: string, name: string, decimals: number }, party: { __typename?: 'Party', id: string } } | null, deposit?: { __typename?: 'Deposit', id: string, status: Types.DepositStatus, createdTimestamp: string, creditedTimestamp?: string | null, txHash?: string | null, asset: { __typename?: 'Asset', id: string, name: string, decimals: number }, party: { __typename?: 'Party', id: string } } | null }; + + +export const ExplorerNodeVoteDocument = gql` + query ExplorerNodeVote($id: ID!) { + withdrawal(id: $id) { + id + status + createdTimestamp + withdrawnTimestamp + txHash + asset { + id + name + decimals + } + party { + id + } + } + deposit(id: $id) { + id + status + createdTimestamp + creditedTimestamp + txHash + asset { + id + name + decimals + } + party { + id + } + } +} + `; + +/** + * __useExplorerNodeVoteQuery__ + * + * To run a query within a React component, call `useExplorerNodeVoteQuery` and pass it any options that fit your needs. + * When your component renders, `useExplorerNodeVoteQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useExplorerNodeVoteQuery({ + * variables: { + * id: // value for 'id' + * }, + * }); + */ +export function useExplorerNodeVoteQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(ExplorerNodeVoteDocument, options); + } +export function useExplorerNodeVoteLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(ExplorerNodeVoteDocument, options); + } +export type ExplorerNodeVoteQueryHookResult = ReturnType; +export type ExplorerNodeVoteLazyQueryHookResult = ReturnType; +export type ExplorerNodeVoteQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/explorer/src/app/components/txs/details/chain-events/index.tsx b/apps/explorer/src/app/components/txs/details/chain-events/index.tsx new file mode 100644 index 000000000..2bb69dc83 --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/index.tsx @@ -0,0 +1,139 @@ +import { TxDetailsChainMultisigThreshold } from './tx-multisig-threshold'; +import { TxDetailsChainMultisigSigner } from './tx-multisig-signer'; +import { TxDetailsChainEventBuiltinDeposit } from './tx-builtin-deposit'; +import { TxDetailsChainEventStakeDeposit } from './tx-stake-deposit'; +import { TxDetailsChainEventStakeRemove } from './tx-stake-remove'; +import { TxDetailsChainEventStakeTotalSupply } from './tx-stake-totalsupply'; +import { TxDetailsChainEventBuiltinWithdrawal } from './tx-builtin-withdrawal'; +import { TxDetailsChainEventErc20AssetList } from './tx-erc20-asset-list'; +import { TxDetailsChainEventErc20AssetLimitsUpdated } from './tx-erc20-asset-limits-updated'; +import { TxDetailsChainEventErc20BridgePause } from './tx-erc20-bridge-pause'; +import { TxDetailsChainEventDeposit } from './tx-erc20-deposit'; + +import isUndefined from 'lodash/isUndefined'; + +import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response'; + +interface ChainEventProps { + txData: BlockExplorerTransactionResult | undefined; +} + +/** + * Inspects the chain event to determine which details view to show. The list of types + * comes from the Swagger document that Block Explorer provides, which can be viewed at + * https://docs.vega.xyz/testnet/api/rest/explorer/block-explorer-list-transactions + * + * This component should have one entry per chain event type, however if there isn't + * a bespoke view for an event the tx-details-shared will still render some basic + * overview and the transaction viewer will still let people view the raw TX. + * + * Most chain events simply render more table rows for the header table + * + * @returns React.JSXElement + */ +export const ChainEvent = ({ txData }: ChainEventProps) => { + const e = txData?.command.chainEvent; + if (!e) { + return null; + } + + // Builtin Asset events + if (e.builtin) { + if (e.builtin.deposit) { + return ; + } + + if (e.builtin?.withdrawal) { + return ( + + ); + } + } + + // ERC20 asset events + if (e.erc20) { + if (e.erc20.deposit) { + return ; + } + + if (e.erc20.withdrawal) { + return ( + + ); + } + + if (e.erc20.assetList) { + return ( + + ); + } + + if (e.erc20.assetLimitsUpdated) { + return ( + + ); + } + + const bridgeStopped = e.erc20.bridgeStopped; + const bridgeResumed = e.erc20.bridgeResumed; + if (!isUndefined(bridgeStopped) || !isUndefined(bridgeResumed)) { + const isPaused = bridgeStopped === false || bridgeResumed === true; + return ; + } + } + + // ERC20 multisig events + if (e.erc20Multisig) { + if (e.erc20Multisig.thresholdSet) { + return ( + + ); + } + + if (e.erc20Multisig.signerAdded) { + return ( + + ); + } + + if (e.erc20Multisig.signerRemoved) { + return ( + + ); + } + } + + // Staking events + if (e.stakingEvent) { + if (e.stakingEvent.stakeDeposited) { + return ( + + ); + } + + if (e.stakingEvent.stakeRemoved) { + return ( + + ); + } + + if (e.stakingEvent.totalSupply) { + return ( + + ); + } + } + + // If we hit this return, tx-shared-details should give a basic overview + return null; +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/lib/get-block-time.ts b/apps/explorer/src/app/components/txs/details/chain-events/lib/get-block-time.ts new file mode 100644 index 000000000..55fd72f0a --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/lib/get-block-time.ts @@ -0,0 +1,16 @@ +/** + * Returns a reasonably formatted time from unix timestamp of block height + * + * @param date String or null date + * @returns String date in locale time + */ +export function getBlockTime(date?: string) { + if (!date) { + return '-'; + } + + const timeInSeconds = parseInt(date, 10); + const timeInMs = timeInSeconds * 1000; + + return new Date(timeInMs).toLocaleString(); +} diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-builtin-deposit.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-builtin-deposit.tsx new file mode 100644 index 000000000..344607257 --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-builtin-deposit.tsx @@ -0,0 +1,46 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; +import type { components } from '../../../../../types/explorer'; +import { AssetLink, PartyLink } from '../../../links'; + +interface TxDetailsChainEventBuiltinDepositProps { + deposit: components['schemas']['vegaBuiltinAssetDeposit']; +} + +/** + * Someone deposited some of a builtin asset. Builtin assets + * have no value outside the Vega chain and should appear only + * on Test networks. + */ +export const TxDetailsChainEventBuiltinDeposit = ({ + deposit, +}: TxDetailsChainEventBuiltinDepositProps) => { + if (!deposit) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + return ( + <> + + {t('Chain Event type')} + {t('Built-in asset deposit')} + + + {t('Recipient')} + + + + + + {t('Asset')} + + ({t('built in asset')}) + + + + {t('Amount')} + {deposit.amount} + + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-builtin-withdrawal.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-builtin-withdrawal.tsx new file mode 100644 index 000000000..70c119d87 --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-builtin-withdrawal.tsx @@ -0,0 +1,47 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; +import type { components } from '../../../../../types/explorer'; +import { AssetLink, PartyLink } from '../../../links'; + +interface TxDetailsChainEventBuiltinDepositProps { + withdrawal: components['schemas']['vegaBuiltinAssetWithdrawal']; +} + +/** + * Someone withdrew some of a builtin asset. Builtin assets + * have no value outside the Vega chain and should appear only + * on Test networks, so someone withdrawing it is pretty rare + */ +export const TxDetailsChainEventBuiltinWithdrawal = ({ + withdrawal, +}: TxDetailsChainEventBuiltinDepositProps) => { + if (!withdrawal) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + return ( + <> + + {t('Chain Event type')} + {t('Built-in asset withdrawal')} + + + {t('Recipient')} + + + + + + {t('Asset')} + + ({t('built in asset')} + ) + + + + {t('Amount')} + {withdrawal.amount} + + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-asset-delist.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-asset-delist.tsx new file mode 100644 index 000000000..f98e08138 --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-asset-delist.tsx @@ -0,0 +1,37 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; +import type { components } from '../../../../../types/explorer'; +import { AssetLink } from '../../../links'; + +interface TxDetailsChainEventErc20AssetDelistProps { + assetDelist: components['schemas']['vegaERC20AssetDelist']; +} + +/** + * An ERC20 asset was removed from the bridge, + * The link should link to an asset that doesn't exist. Which feels odd + * but I think is better than having no link - in case something + * weird is up and it still exists + */ +export const TxDetailsChainEventErc20AssetDelist = ({ + assetDelist, +}: TxDetailsChainEventErc20AssetDelistProps) => { + if (!assetDelist) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + return ( + <> + + {t('Chain event type')} + {t('ERC20 asset removed')} + + + {t('Removed Vega asset')} + + + + + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-asset-limits-updated.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-asset-limits-updated.tsx new file mode 100644 index 000000000..9082195c0 --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-asset-limits-updated.tsx @@ -0,0 +1,65 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; +import type { components } from '../../../../../types/explorer'; +import { AssetLink } from '../../../links'; +import { + EthExplorerLink, + EthExplorerLinkTypes, +} from '../../../links/eth-explorer-link/eth-explorer-link'; + +interface TxDetailsChainEventErc20AssetLimitsUpdatedProps { + assetLimitsUpdated: components['schemas']['vegaERC20AssetLimitsUpdated']; +} + +/** + * An ERC20 asset was had its limits changed. The limits are in place + * at first to prevent users depositing large sums while the network + * is still new, as a safety measure. + * - Lifetime limit is how much can be withdrawn of this asset to a + * single ethereum address + * - Withdraw threshold is the size of a withdrawal that will incur + * a delay in processing. The delay is set by a network parameter + */ +export const TxDetailsChainEventErc20AssetLimitsUpdated = ({ + assetLimitsUpdated, +}: TxDetailsChainEventErc20AssetLimitsUpdatedProps) => { + if (!assetLimitsUpdated) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + return ( + <> + + {t('Chain event type')} + {t('ERC20 asset limits updated')} + + + {assetLimitsUpdated.sourceEthereumAddress ? ( + + {t('ERC20 asset')} + + + + + ) : null} + + + {t('Vega asset')} + + + + + + {t('Total lifetime limit')} + {assetLimitsUpdated.lifetimeLimits} + + + {t('Asset withdrawal threshold')} + {assetLimitsUpdated.withdrawThreshold} + + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-asset-list.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-asset-list.tsx new file mode 100644 index 000000000..0674c9d88 --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-asset-list.tsx @@ -0,0 +1,51 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; +import type { components } from '../../../../../types/explorer'; +import { AssetLink } from '../../../links'; +import { + EthExplorerLink, + EthExplorerLinkTypes, +} from '../../../links/eth-explorer-link/eth-explorer-link'; + +interface TxDetailsChainEventErc20AssetListProps { + assetList: components['schemas']['vegaERC20AssetList']; +} + +/** + * An ERC20 asset was proposed and then enacted on the bridge, + * a Asset List event will be emitted that tells the core to + * create the asset. That's this event - it's very basic + */ +export const TxDetailsChainEventErc20AssetList = ({ + assetList, +}: TxDetailsChainEventErc20AssetListProps) => { + if (!assetList) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + return ( + <> + + {t('Chain event type')} + {t('ERC20 asset added')} + + {assetList.assetSource ? ( + + {t('Source')} + + + + + ) : null} + + {t('Added Vega asset')} + + + + + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-bridge-pause.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-bridge-pause.tsx new file mode 100644 index 000000000..3b840b6b3 --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-bridge-pause.tsx @@ -0,0 +1,24 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; + +interface TxDetailsChainEventErc20BridgePauseProps { + isPaused: boolean; +} + +/** + * The bridge was either paused or unpaused, preventing withdrawals + * or deposits from being enacted. This will only happen if the + * validators have signed a multisig bundle requiring it to happen + */ +export const TxDetailsChainEventErc20BridgePause = ({ + isPaused, +}: TxDetailsChainEventErc20BridgePauseProps) => { + const event = isPaused ? 'pause' : 'unpaused'; + + return ( + + {t('Chain event type')} + {t(`ERC20 bridge ${event}`)} + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-deposit.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-deposit.tsx new file mode 100644 index 000000000..fffc5011d --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-deposit.tsx @@ -0,0 +1,59 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; +import type { components } from '../../../../../types/explorer'; +import { AssetLink, PartyLink } from '../../../links'; +import { + EthExplorerLink, + EthExplorerLinkTypes, +} from '../../../links/eth-explorer-link/eth-explorer-link'; + +interface TxDetailsChainEventProps { + deposit: components['schemas']['vegaERC20Deposit']; +} + +/** + * Someone deposited some erc20 + */ +export const TxDetailsChainEventDeposit = ({ + deposit, +}: TxDetailsChainEventProps) => { + if (!deposit) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + return ( + <> + + {t('Chain event type')} + {t('ERC20 deposit')} + + {deposit.sourceEthereumAddress ? ( + + {t('Source')} + + + + + ) : null} + + {t('Recipient')} + + + + + + {t('Asset')} + + + + + + {t('Amount')} + {deposit.amount} + + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-withdrawal.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-withdrawal.tsx new file mode 100644 index 000000000..923eb0046 --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-erc20-withdrawal.tsx @@ -0,0 +1,51 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; +import type { components } from '../../../../../types/explorer'; +import { AssetLink } from '../../../links'; +import { + EthExplorerLink, + EthExplorerLinkTypes, +} from '../../../links/eth-explorer-link/eth-explorer-link'; + +interface TxDetailsChainEventWithdrawalProps { + withdrawal: components['schemas']['vegaERC20Withdrawal']; +} + +/** + * Someone deposited some erc20 + */ +export const TxDetailsChainEventWithdrawal = ({ + withdrawal, +}: TxDetailsChainEventWithdrawalProps) => { + if (!withdrawal) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + return ( + <> + + {t('Chain event type')} + {t('ERC20 withdrawal')} + + + {withdrawal.targetEthereumAddress ? ( + + {t('Recipient')} + + + + + ) : null} + + + {t('Asset')} + + + + + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-multisig-signer.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-multisig-signer.tsx new file mode 100644 index 000000000..f5328e4a1 --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-multisig-signer.tsx @@ -0,0 +1,50 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; +import type { components } from '../../../../../types/explorer'; +import { getBlockTime } from './lib/get-block-time'; + +interface TxDetailsChainMultisigSignerProps { + signer: + | components['schemas']['vegaERC20SignerAdded'] + | components['schemas']['vegaERC20SignerRemoved']; +} + +/** + * Someone updated multsig signer set, either removing or adding someone + */ +export const TxDetailsChainMultisigSigner = ({ + signer, +}: TxDetailsChainMultisigSignerProps) => { + if (!signer) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + const blockTime = getBlockTime(signer.blockTime); + const target = + 'newSigner' in signer + ? signer.newSigner + : 'oldSigner' in signer + ? signer.oldSigner + : ''; + + return ( + <> + + {t('Chain Event type')} + {'newSigner' in signer + ? t('Add ERC20 bridge multisig signer') + : t('Remove ERC20 bridge multsig signer')} + + + + {'newSigner' in signer ? t('Add signer') : t('Remove signer')} + + {target} + + + {t('Signer change at')} + {blockTime} + + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-multisig-threshold.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-multisig-threshold.tsx new file mode 100644 index 000000000..d26e354d9 --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-multisig-threshold.tsx @@ -0,0 +1,59 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; +import type { components } from '../../../../../types/explorer'; +import isNumber from 'lodash/isNumber'; + +/** + * Returns a reasonably formatted time from unix timestamp of block height + * + * @param date String or null date + * @returns String date in locale time + */ +function getBlockTime(date?: string) { + if (!date) { + return '-'; + } + + const timeInSeconds = parseInt(date, 10); + const timeInMs = timeInSeconds * 1000; + + return new Date(timeInMs).toLocaleString(); +} + +interface TxDetailsChainMultisigThresholdProps { + thresholdSet: components['schemas']['vegaERC20MultiSigEvent']['thresholdSet']; +} + +/** + * Someone updated multsig threshold value on the smart contract. + * It's a percentage, with 1000 being 100% and 0 being 0%. + */ +export const TxDetailsChainMultisigThreshold = ({ + thresholdSet, +}: TxDetailsChainMultisigThresholdProps) => { + if (!thresholdSet) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + const blockTime = getBlockTime(thresholdSet.blockTime); + const threshold = isNumber(thresholdSet.newThreshold) + ? thresholdSet.newThreshold / 10 + : '-'; + + return ( + <> + + {t('Chain Event type')} + {t('ERC20 multisig threshold set')} + + + {t('Threshold')} + {threshold}% + + + {t('Threshold set from')} + {blockTime} + + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-stake-deposit.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-stake-deposit.tsx new file mode 100644 index 000000000..48db4281f --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-stake-deposit.tsx @@ -0,0 +1,49 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; +import type { components } from '../../../../../types/explorer'; +import { PartyLink } from '../../../links'; + +interface TxDetailsChainEventStakeDepositProps { + deposit: components['schemas']['vegaStakeDeposited']; +} + +/** + * Someone addedd some stake for a particular party + * This should link to the Governance asset, but doesn't + * as that would require checking the Network Paramters + * Ethereum address should also be a link to an ETH block explorer + */ +export const TxDetailsChainEventStakeDeposit = ({ + deposit, +}: TxDetailsChainEventStakeDepositProps) => { + if (!deposit) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + return ( + <> + + {t('Chain Event type')} + {t('Stake deposited')} + + + {t('Source')} + {deposit.ethereumAddress || ''} + + + {t('Recipient')} + + + + + + {t('Amount')} + {deposit.amount} + + + {t('Deposited at')} + {deposit.amount} + + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-stake-remove.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-stake-remove.tsx new file mode 100644 index 000000000..4dcc51faa --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-stake-remove.tsx @@ -0,0 +1,49 @@ +import { t } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; +import type { components } from '../../../../../types/explorer'; +import { PartyLink } from '../../../links'; + +interface TxDetailsChainEventStakeRemoveProps { + remove: components['schemas']['vegaStakeRemoved']; +} + +/** + * Someone addedd some stake for a particular party + * This should link to the Governance asset, but doesn't + * as that would require checking the Network Parameters + * Ethereum address should also be a link to an ETH block explorer + */ +export const TxDetailsChainEventStakeRemove = ({ + remove, +}: TxDetailsChainEventStakeRemoveProps) => { + if (!remove) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + return ( + <> + + {t('Chain Event type')} + {t('Stake removed')} + + + {t('Source')} + {remove.ethereumAddress || ''} + + + {t('Recipient')} + + + + + + {t('Amount')} + {remove.amount} + + + {t('Deposited at')} + {remove.blockTime} + + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/chain-events/tx-stake-totalsupply.tsx b/apps/explorer/src/app/components/txs/details/chain-events/tx-stake-totalsupply.tsx new file mode 100644 index 000000000..1cdf07120 --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/chain-events/tx-stake-totalsupply.tsx @@ -0,0 +1,54 @@ +import { formatNumber, t, toBigNum } from '@vegaprotocol/react-helpers'; +import { TableRow, TableCell } from '../../../table'; +import type { components } from '../../../../../types/explorer'; +import { + EthExplorerLink, + EthExplorerLinkTypes, +} from '../../../links/eth-explorer-link/eth-explorer-link'; + +interface TxDetailsChainEventStakeTotalSupplyProps { + update: components['schemas']['vegaStakeTotalSupply']; +} + +/** + * Chain event set the total supply of the governance asset + * Happens whenever the total supply changes, or when the chain + * restarts and the total supply is detected. + */ +export const TxDetailsChainEventStakeTotalSupply = ({ + update, +}: TxDetailsChainEventStakeTotalSupplyProps) => { + if (!update) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + let totalSupply = update.totalSupply || ''; + if (totalSupply.length > 0) { + totalSupply = formatNumber(toBigNum(totalSupply, 18)); + } + + return ( + <> + + {t('Chain Event type')} + {t('Stake total supply update')} + + + {update.tokenAddress ? ( + + {t('Source')} + + + + + ) : null} + + {t('Total supply')} + {totalSupply} + + + ); +}; diff --git a/apps/explorer/src/app/components/txs/details/node-vote.graphql b/apps/explorer/src/app/components/txs/details/node-vote.graphql new file mode 100644 index 000000000..b9184101d --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/node-vote.graphql @@ -0,0 +1,32 @@ +query ExplorerNodeVote($id: ID!) { + withdrawal(id: $id) { + id + status + createdTimestamp + withdrawnTimestamp + txHash + asset { + id + name + decimals + } + party { + id + } + } + deposit(id: $id) { + id + status + createdTimestamp + creditedTimestamp + txHash + asset { + id + name + decimals + } + party { + id + } + } +} diff --git a/apps/explorer/src/app/components/txs/details/shared/tx-details-shared.tsx b/apps/explorer/src/app/components/txs/details/shared/tx-details-shared.tsx index 604667de7..fb35539dc 100644 --- a/apps/explorer/src/app/components/txs/details/shared/tx-details-shared.tsx +++ b/apps/explorer/src/app/components/txs/details/shared/tx-details-shared.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { t } from '@vegaprotocol/react-helpers'; import { TableRow, TableCell } from '../../../table'; import { BlockLink, PartyLink } from '../../../links/'; @@ -6,6 +5,7 @@ import { TimeAgo } from '../../../time-ago'; import type { BlockExplorerTransactionResult } from '../../../../routes/types/block-explorer-response'; import type { TendermintBlocksResponse } from '../../../../routes/blocks/tendermint-blocks-response'; +import { Time } from '../../../time'; interface TxDetailsSharedProps { txData: BlockExplorerTransactionResult | undefined; @@ -29,11 +29,6 @@ export const TxDetailsShared = ({ const time: string = blockData?.result.block.header.time || ''; const height: string = blockData?.result.block.header.height || ''; - let timeFormatted = ''; - - if (time) { - timeFormatted = new Date(time).toLocaleString(); - } return ( <> @@ -56,7 +51,9 @@ export const TxDetailsShared = ({ {time ? (
- {timeFormatted} + + diff --git a/apps/explorer/src/app/components/txs/details/tx-batch.tsx b/apps/explorer/src/app/components/txs/details/tx-batch.tsx index 01008989b..d9d34932e 100644 --- a/apps/explorer/src/app/components/txs/details/tx-batch.tsx +++ b/apps/explorer/src/app/components/txs/details/tx-batch.tsx @@ -1,9 +1,5 @@ -import React from 'react'; import { t } from '@vegaprotocol/react-helpers'; -import type { - BlockExplorerTransactionResult, - BatchMarketInstructions, -} from '../../../routes/types/block-explorer-response'; +import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response'; import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response'; import { TxDetailsShared } from './shared/tx-details-shared'; import { TableWithTbody, TableRow, TableCell } from '../../table'; @@ -26,16 +22,17 @@ export const TxDetailsBatch = ({ pubKey, blockData, }: TxDetailsBatchProps) => { - if (!txData) { + if (!txData || !txData.command.batchMarketInstructions) { return <>{t('Awaiting Block Explorer transaction details')}; } - const cmd = txData.command as BatchMarketInstructions; - - const batchSubmissions = cmd.batchMarketInstructions.submissions.length; - const batchAmendments = cmd.batchMarketInstructions.amendments.length; - const batchCancellations = cmd.batchMarketInstructions.cancellations.length; - const batchTotal = batchSubmissions + batchAmendments + batchCancellations; + const countSubmissions = + txData.command.batchMarketInstructions.submissions?.length || 0; + const countAmendments = + txData.command.batchMarketInstructions.amendments?.length || 0; + const countCancellations = + txData.command.batchMarketInstructions.cancellations?.length || 0; + const countTotal = countSubmissions + countAmendments + countCancellations; return ( @@ -43,7 +40,7 @@ export const TxDetailsBatch = ({ {t('Batch size')} - {batchTotal} + {countTotal} @@ -51,7 +48,7 @@ export const TxDetailsBatch = ({ {t('Submissions')} - {batchSubmissions} + {countSubmissions} @@ -59,7 +56,7 @@ export const TxDetailsBatch = ({ {t('Amendments')} - {batchAmendments} + {countAmendments} @@ -67,7 +64,7 @@ export const TxDetailsBatch = ({ {t('Cancellations')} - {batchCancellations} + {countCancellations} diff --git a/apps/explorer/src/app/components/txs/details/tx-chain-event.tsx b/apps/explorer/src/app/components/txs/details/tx-chain-event.tsx index 66d1cb09e..7d6c93822 100644 --- a/apps/explorer/src/app/components/txs/details/tx-chain-event.tsx +++ b/apps/explorer/src/app/components/txs/details/tx-chain-event.tsx @@ -1,13 +1,10 @@ -import React from 'react'; import { t } from '@vegaprotocol/react-helpers'; -import type { - BlockExplorerTransactionResult, - ChainEvent, -} from '../../../routes/types/block-explorer-response'; -import { AssetLink, PartyLink } 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 { TableWithTbody } from '../../table'; + +import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response'; +import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response'; +import { ChainEvent } from './chain-events'; interface TxDetailsChainEventProps { txData: BlockExplorerTransactionResult | undefined; @@ -20,10 +17,10 @@ interface TxDetailsChainEventProps { * Multiple events will relay the same data, from each validator, so that the * deposit/withdrawal can be verified independently. * - * Design considerations so far: - * - The ethereum address should be a link to an Ethereum explorer - * - Sender and recipient are shown because they are easy - * - Amount is not shown because there is no formatter by asset component + * There are so many chain events that the specific components have been broken + * out in to individual components. `getChainEventComponent` determines which + * is the most appropriate based on the transaction shape. See that function + * for more information. */ export const TxDetailsChainEvent = ({ txData, @@ -33,32 +30,11 @@ export const TxDetailsChainEvent = ({ if (!txData) { return <>{t('Awaiting Block Explorer transaction details')}; } - const cmd = txData.command as ChainEvent; - const assetId = cmd.chainEvent.erc20.deposit.vegaAssetId; - const sender = cmd.chainEvent.erc20.deposit.sourceEthereumAddress; - const recipient = cmd.chainEvent.erc20.deposit.targetPartyId; return ( - - {t('Asset')} - - - - - - {t('Sender')} - - {sender} - - - - {t('Recipient')} - - - - + ); }; diff --git a/apps/explorer/src/app/components/txs/details/tx-details-wrapper.tsx b/apps/explorer/src/app/components/txs/details/tx-details-wrapper.tsx index b6daec5fc..413a46c9a 100644 --- a/apps/explorer/src/app/components/txs/details/tx-details-wrapper.tsx +++ b/apps/explorer/src/app/components/txs/details/tx-details-wrapper.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from 'react'; +import { useMemo } from 'react'; import { DATA_SOURCES } from '../../../config'; import { t, useFetch } from '@vegaprotocol/react-helpers'; import { TxDetailsOrder } from './tx-order'; @@ -10,11 +10,10 @@ import { TxDetailsGeneric } from './tx-generic'; import { TxDetailsBatch } from './tx-batch'; import { TxDetailsChainEvent } from './tx-chain-event'; import { TxContent } from '../../../routes/txs/id/tx-content'; - -type resultOrNull = BlockExplorerTransactionResult | undefined; +import { TxDetailsNodeVote } from './tx-node-vote'; interface TxDetailsWrapperProps { - txData: resultOrNull; + txData: BlockExplorerTransactionResult | undefined; pubKey: string | undefined; height: string; } @@ -61,7 +60,7 @@ export const TxDetailsWrapper = ({ * @param txData * @returns JSX.Element */ -function getTransactionComponent(txData: resultOrNull) { +function getTransactionComponent(txData?: BlockExplorerTransactionResult) { if (!txData) { return TxDetailsGeneric; } @@ -77,6 +76,8 @@ function getTransactionComponent(txData: resultOrNull) { return TxDetailsBatch; case 'Chain Event': return TxDetailsChainEvent; + case 'Node Vote': + return TxDetailsNodeVote; default: return TxDetailsGeneric; } diff --git a/apps/explorer/src/app/components/txs/details/tx-generic.tsx b/apps/explorer/src/app/components/txs/details/tx-generic.tsx index eabd333cb..2d0ced7d5 100644 --- a/apps/explorer/src/app/components/txs/details/tx-generic.tsx +++ b/apps/explorer/src/app/components/txs/details/tx-generic.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { t } from '@vegaprotocol/react-helpers'; import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response'; import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response'; diff --git a/apps/explorer/src/app/components/txs/details/tx-hearbeat.tsx b/apps/explorer/src/app/components/txs/details/tx-hearbeat.tsx index 7db5f9147..2318bded0 100644 --- a/apps/explorer/src/app/components/txs/details/tx-hearbeat.tsx +++ b/apps/explorer/src/app/components/txs/details/tx-hearbeat.tsx @@ -1,9 +1,5 @@ -import React from 'react'; import { t } from '@vegaprotocol/react-helpers'; -import type { - BlockExplorerTransactionResult, - ValidatorHeartbeat, -} from '../../../routes/types/block-explorer-response'; +import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response'; import { BlockLink, NodeLink } from '../../links/'; import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response'; import { TxDetailsShared } from './shared/tx-details-shared'; @@ -56,11 +52,12 @@ export const TxDetailsHeartbeat = ({ pubKey, blockData, }: TxDetailsHeartbeatProps) => { - if (!txData) { + if (!txData || !txData.command.validatorHeartbeat) { return <>{t('Awaiting Block Explorer transaction details')}; } - const cmd = txData.command as ValidatorHeartbeat; + const nodeId = txData.command.validatorHeartbeat.nodeId || ''; + const blockHeight = txData.command.blockHeight || ''; return ( @@ -68,18 +65,18 @@ export const TxDetailsHeartbeat = ({ {t('Node')} - + {t('Signed block height')} - + {t('Freshness (lower is better)')} - {scoreFreshness(txData.block, cmd.blockHeight)} + {scoreFreshness(txData.block, blockHeight)} ); diff --git a/apps/explorer/src/app/components/txs/details/tx-lp-amend.tsx b/apps/explorer/src/app/components/txs/details/tx-lp-amend.tsx index b72403bf9..c44a40a0b 100644 --- a/apps/explorer/src/app/components/txs/details/tx-lp-amend.tsx +++ b/apps/explorer/src/app/components/txs/details/tx-lp-amend.tsx @@ -1,9 +1,5 @@ -import React from 'react'; import { t } from '@vegaprotocol/react-helpers'; -import type { - AmendLiquidityProvisionOrder, - BlockExplorerTransactionResult, -} from '../../../routes/types/block-explorer-response'; +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'; @@ -29,7 +25,7 @@ export const TxDetailsLPAmend = ({ return <>{t('Awaiting Block Explorer transaction details')}; } - const cmd = txData.command as AmendLiquidityProvisionOrder; + const marketId = txData.command.liquidityProvisionAmendment?.marketId || ''; return ( @@ -37,7 +33,7 @@ export const TxDetailsLPAmend = ({ {t('Market')} - + diff --git a/apps/explorer/src/app/components/txs/details/tx-node-vote.tsx b/apps/explorer/src/app/components/txs/details/tx-node-vote.tsx new file mode 100644 index 000000000..0ab5a54d1 --- /dev/null +++ b/apps/explorer/src/app/components/txs/details/tx-node-vote.tsx @@ -0,0 +1,144 @@ +import { t } from '@vegaprotocol/react-helpers'; +import type { BlockExplorerTransactionResult } from '../../../routes/types/block-explorer-response'; +import type { TendermintBlocksResponse } from '../../../routes/blocks/tendermint-blocks-response'; +import { TxDetailsShared } from './shared/tx-details-shared'; +import { TableCell, TableRow, TableWithTbody } from '../../table'; +import type { ExplorerNodeVoteQueryResult } from './__generated___/node-vote'; +import { useExplorerNodeVoteQuery } from './__generated___/node-vote'; +import { PartyLink } from '../../links'; +import { Time } from '../../time'; + +interface TxDetailsNodeVoteProps { + txData: BlockExplorerTransactionResult | undefined; + pubKey: string | undefined; + blockData: TendermintBlocksResponse | undefined; +} + +/** + * If there is not yet a custom component for a transaction, just display + * the basic details. This allows someone to view the decoded transaction. + */ +export const TxDetailsNodeVote = ({ + txData, + pubKey, + blockData, +}: TxDetailsNodeVoteProps) => { + const id = txData?.command.nodeVote?.reference || ''; + + const { data } = useExplorerNodeVoteQuery({ + variables: { + id, + }, + // Required as one of these queries will needlessly error + errorPolicy: 'ignore', + }); + + if (!txData) { + return <>{t('Awaiting Block Explorer transaction details')}; + } + + return ( + + + {data && !!data.deposit + ? TxDetailsNodeVoteDeposit({ deposit: data }) + : data && !!data.withdrawal + ? TxDetailsNodeVoteWithdrawal({ withdrawal: data }) + : null} + + ); +}; + +interface TxDetailsNodeVoteDepositProps { + deposit: ExplorerNodeVoteQueryResult['data']; +} + +export function TxDetailsNodeVoteDeposit({ + deposit, +}: TxDetailsNodeVoteDepositProps) { + if (!deposit) { + return null; + } + return ( + <> + + {t('Witnessed Event type')} + {deposit?.deposit?.txHash ? ( + {t('ERC20 deposit')} + ) : ( + {t('Built-in asset deposit')} + )} + + + {t('To party')}: + + + + + + {t('Credited on')}: + + + {deposit?.deposit?.txHash ? ( + + ) : null} + + + ); +} + +interface TxDetailsNodeVoteWithdrawalProps { + withdrawal: ExplorerNodeVoteQueryResult['data']; +} + +export function TxDetailsNodeVoteWithdrawal({ + withdrawal, +}: TxDetailsNodeVoteWithdrawalProps) { + if (!withdrawal) { + return null; + } + return ( + <> + + {t('Witnessed Event type')} + {withdrawal?.withdrawal?.txHash ? ( + {t('ERC20 withdrawal')} + ) : ( + {t('Built-in asset withdrawal')} + )} + + + {t('From party')}: + + + + + + {t('Withdrawn on')}: + + + {withdrawal?.withdrawal?.txHash ? ( + + ) : null} + + + ); +} + +interface TxDetailsEthTxHashProps { + hash: string; +} + +export function TxHash({ hash }: TxDetailsEthTxHashProps) { + if (!hash) { + return null; + } + return ( + + Ethereum TX: + {hash} + + ); +} diff --git a/apps/explorer/src/app/components/txs/details/tx-order.tsx b/apps/explorer/src/app/components/txs/details/tx-order.tsx index 3e0182b45..0f425fc5f 100644 --- a/apps/explorer/src/app/components/txs/details/tx-order.tsx +++ b/apps/explorer/src/app/components/txs/details/tx-order.tsx @@ -1,9 +1,5 @@ -import React from 'react'; import { t } from '@vegaprotocol/react-helpers'; -import type { - BlockExplorerTransactionResult, - SubmitOrder, -} from '../../../routes/types/block-explorer-response'; +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'; @@ -26,11 +22,10 @@ export const TxDetailsOrder = ({ pubKey, blockData, }: TxDetailsOrderProps) => { - if (!txData) { + if (!txData || !txData.command.orderSubmission) { return <>{t('Awaiting Block Explorer transaction details')}; } - - const cmd = txData.command as SubmitOrder; + const marketId = txData.command.orderSubmission.marketId || '-'; return ( @@ -38,7 +33,7 @@ export const TxDetailsOrder = ({ {t('Market')} - + diff --git a/apps/explorer/src/app/components/txs/tx-order-type.tsx b/apps/explorer/src/app/components/txs/tx-order-type.tsx index 5c851255d..72ea9774a 100644 --- a/apps/explorer/src/app/components/txs/tx-order-type.tsx +++ b/apps/explorer/src/app/components/txs/tx-order-type.tsx @@ -1,5 +1,9 @@ +import { t } from '@vegaprotocol/react-helpers'; +import type { components } from '../../../types/explorer'; + interface TxOrderTypeProps { orderType: string; + chainEvent?: components['schemas']['v1ChainEvent']; className?: string; } @@ -32,13 +36,73 @@ const displayString: StringMap = { ValidatorHeartbeat: 'Validator Heartbeat', }; -export const TxOrderType = ({ orderType }: TxOrderTypeProps) => { +/** + * Given a chain event, will try to provide a more useful label + * @param chainEvent + * @returns + */ +export function getLabelForChainEvent( + chainEvent: components['schemas']['v1ChainEvent'] +): string { + if (chainEvent.builtin) { + if (chainEvent.builtin.deposit) { + return t('Built-in deposit'); + } else if (chainEvent.builtin.withdrawal) { + return t('Built-in withdraw'); + } + return t('Built-in event'); + } else if (chainEvent.erc20) { + if (chainEvent.erc20.assetDelist) { + return t('ERC20 delist'); + } else if (chainEvent.erc20.assetList) { + return t('ERC20 list'); + } else if (chainEvent.erc20.bridgeResumed) { + return t('Bridge resume'); + } else if (chainEvent.erc20.bridgeStopped) { + return t('Bridge pause'); + } else if (chainEvent.erc20.deposit) { + return t('ERC20 deposit'); + } else if (chainEvent.erc20.withdrawal) { + return t('ERC20 withdraw'); + } + return t('ERC20 event'); + } else if (chainEvent.stakingEvent) { + if (chainEvent.stakingEvent.stakeDeposited) { + return t('Stake add'); + } else if (chainEvent.stakingEvent.stakeRemoved) { + return t('Stake remove'); + } + return t('Staking event'); + } else if (chainEvent.erc20Multisig) { + if (chainEvent.erc20Multisig.signerAdded) { + return t('Signer adde'); + } else if (chainEvent.erc20Multisig.signerRemoved) { + return t('Signer remove'); + } else if (chainEvent.erc20Multisig.thresholdSet) { + return t('Signer threshold'); + } + return t('Multisig update'); + } + return t('Chain Event'); +} + +export const TxOrderType = ({ orderType, chainEvent }: TxOrderTypeProps) => { + let type = displayString[orderType] || orderType; + + let colours = 'text-white dark:text-white bg-zinc-800 dark:bg-zinc-800'; + + // This will get unwieldy and should probably produce a different colour of tag + if (type === 'Chain Event' && !!chainEvent) { + type = getLabelForChainEvent(chainEvent); + colours = + 'text-white dark-text-white bg-vega-pink-dark dark:bg-vega-pink-dark'; + } return (
- {displayString[orderType] || orderType} + {type}
); }; diff --git a/apps/explorer/src/app/components/txs/txs-infinite-list-item.tsx b/apps/explorer/src/app/components/txs/txs-infinite-list-item.tsx index 6214b7a8e..f9420b6b3 100644 --- a/apps/explorer/src/app/components/txs/txs-infinite-list-item.tsx +++ b/apps/explorer/src/app/components/txs/txs-infinite-list-item.tsx @@ -13,6 +13,7 @@ export const TxsInfiniteListItem = ({ type, block, index, + command, }: Partial) => { if ( !hash || @@ -54,7 +55,7 @@ export const TxsInfiniteListItem = ({ />
- +
{ expiresAt: '1664966445481288736', type: 'TYPE_LIMIT', reference: 'traderbot', - peggedOrder: null, + peggedOrder: undefined, }, }, })); diff --git a/apps/explorer/src/app/components/txs/txs-infinite-list.tsx b/apps/explorer/src/app/components/txs/txs-infinite-list.tsx index a5378b765..93b5070f7 100644 --- a/apps/explorer/src/app/components/txs/txs-infinite-list.tsx +++ b/apps/explorer/src/app/components/txs/txs-infinite-list.tsx @@ -93,7 +93,7 @@ export const TxsInfiniteList = ({ {({ onItemsRendered, ref }) => ( { - {decodedBlockData.map(({ TxHash, PubKey, Type }) => { + {decodedBlockData.map(({ TxHash, PubKey, Type, Command }) => { + const chainEvent = JSON.parse(Command || ''); + return ( { /> - + ); diff --git a/apps/explorer/src/app/config/env.ts b/apps/explorer/src/app/config/env.ts index 55c18bc4f..47493cc83 100644 --- a/apps/explorer/src/app/config/env.ts +++ b/apps/explorer/src/app/config/env.ts @@ -16,6 +16,7 @@ export const ENV = { blockExplorerUrl: windowOrDefault('NX_BLOCK_EXPLORER'), tendermintUrl: windowOrDefault('NX_TENDERMINT_URL'), tendermintWebsocketUrl: windowOrDefault('NX_TENDERMINT_WEBSOCKET_URL'), + ethExplorerUrl: windowOrDefault('NX_ETHERSCAN_URL'), }, flags: { assets: truthy.includes(windowOrDefault('NX_EXPLORER_ASSETS')), diff --git a/apps/explorer/src/app/routes/types/block-explorer-response.d.ts b/apps/explorer/src/app/routes/types/block-explorer-response.d.ts index 31bd0049a..6fd02ff31 100644 --- a/apps/explorer/src/app/routes/types/block-explorer-response.d.ts +++ b/apps/explorer/src/app/routes/types/block-explorer-response.d.ts @@ -1,3 +1,4 @@ +import type { components } from '../../../types/explorer'; import type { UnknownObject } from '../../components/nested-data-list'; export interface BlockExplorerTransactionResult { @@ -8,13 +9,7 @@ export interface BlockExplorerTransactionResult { type: string; code: number; cursor: string; - command: - | ValidatorHeartbeat - | SubmitOrder - | StateVariableProposal - | AmendLiquidityProvisionOrder - | BatchMarketInstructions - | ChainEvent; + command: components['schemas']['v1InputData']; } export interface BlockExplorerTransactions { @@ -103,16 +98,23 @@ export interface BatchCancellationInstruction { export interface ChainEvent { blockHeight: string; nonce: string; - chainEvent: { - erc20: { - deposit: ERC20Deposit; - }; + chainEvent: components['schemas']['v1ChainEvent']; +} + +export interface ChainEventErc20Multisig { + erc20Multisig: { + block: string; + index: string; }; } -export interface ERC20Deposit { - vegaAssetId: string; - sourceEthereumAddress: string; - targetPartyId: string; - amount: string; +export interface ChainEventErc20Deposit { + erc20: { + deposit: { + vegaAssetId: string; + sourceEthereumAddress: string; + targetPartyId: string; + amount: string; + }; + }; } diff --git a/apps/explorer/src/types/explorer.d.ts b/apps/explorer/src/types/explorer.d.ts new file mode 100644 index 000000000..324e152c7 --- /dev/null +++ b/apps/explorer/src/types/explorer.d.ts @@ -0,0 +1,1563 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +/** Type helpers */ +type Without = { [P in Exclude]?: never }; +type XOR = T | U extends object + ? (Without & U) | (Without & T) + : T | U; +/* eslint-disable @typescript-eslint/no-explicit-any */ +type OneOf = T extends [infer Only] + ? Only + : T extends [infer A, infer B, ...infer Rest] + ? OneOf<[XOR, ...Rest]> + : never; +/* typescript-eslint:enable no-explicit-any */ + +export interface paths { + '/transactions': { + /** + * List transactions + * @description List transactions from the Vega blockchain + */ + get: operations['BlockExplorer_ListTransactions']; + }; + '/transactions/{hash}': { + /** + * Get transaction + * @description Get a transaction from the Vega blockchain + */ + get: operations['BlockExplorer_GetTransaction']; + }; +} + +export interface components { + schemas: { + /** + * @description Comparator describes the type of comparison. + * + * - OPERATOR_UNSPECIFIED: The default value + * - OPERATOR_EQUALS: Verify if the property values are strictly equal or not. + * - OPERATOR_GREATER_THAN: Verify if the data source data value is greater than the Condition value. + * - OPERATOR_GREATER_THAN_OR_EQUAL: Verify if the data source data value is greater than or equal to the Condition + * value. + * - OPERATOR_LESS_THAN: Verify if the data source data value is less than the Condition value. + * - OPERATOR_LESS_THAN_OR_EQUAL: Verify if the data source data value is less or equal to than the Condition + * value. + * @default OPERATOR_UNSPECIFIED + * @enum {string} + */ + readonly ConditionOperator: + | 'OPERATOR_UNSPECIFIED' + | 'OPERATOR_EQUALS' + | 'OPERATOR_GREATER_THAN' + | 'OPERATOR_GREATER_THAN_OR_EQUAL' + | 'OPERATOR_LESS_THAN' + | 'OPERATOR_LESS_THAN_OR_EQUAL'; + /** + * The supported Oracle sources + * @description - ORACLE_SOURCE_UNSPECIFIED: The default value + * - ORACLE_SOURCE_OPEN_ORACLE: Specifies that the payload will be base64 encoded JSON conforming to the Open Oracle standard + * - ORACLE_SOURCE_JSON: Specifies that the payload will be base64 encoded JSON, but does not specify the shape of the data + * @default ORACLE_SOURCE_UNSPECIFIED + * @enum {string} + */ + readonly OracleDataSubmissionOracleSource: + | 'ORACLE_SOURCE_UNSPECIFIED' + | 'ORACLE_SOURCE_OPEN_ORACLE' + | 'ORACLE_SOURCE_JSON'; + /** + * Time In Force for an order + * @description - TIME_IN_FORCE_UNSPECIFIED: Default value for TimeInForce, can be valid for an amend + * - TIME_IN_FORCE_GTC: Good until cancelled, the order trades any amount and as much as possible + * and remains on the book until it either trades completely or is cancelled + * - TIME_IN_FORCE_GTT: Good until specified time, this order type trades any amount and as much as possible + * and remains on the book until it either trades completely, is cancelled, or expires at a set time + * NOTE: this may in future be multiple types or have sub types for orders that provide different ways of specifying expiry + * - TIME_IN_FORCE_IOC: Immediate or cancel, the order trades any amount and as much as possible + * but does not remain on the book (whether it trades or not) + * - TIME_IN_FORCE_FOK: Fill or kill, The order either trades completely (remainingSize == 0 after adding) + * or not at all, does not remain on the book if it doesn't trade + * - TIME_IN_FORCE_GFA: Good for auction, this order is only accepted during an auction period + * - TIME_IN_FORCE_GFN: Good for normal, this order is only accepted during normal trading (that can be continuous trading or frequent batched auctions) + * @default TIME_IN_FORCE_UNSPECIFIED + * @enum {string} + */ + readonly OrderTimeInForce: + | 'TIME_IN_FORCE_UNSPECIFIED' + | 'TIME_IN_FORCE_GTC' + | 'TIME_IN_FORCE_GTT' + | 'TIME_IN_FORCE_IOC' + | 'TIME_IN_FORCE_FOK' + | 'TIME_IN_FORCE_GFA' + | 'TIME_IN_FORCE_GFN'; + /** + * @default METHOD_UNSPECIFIED + * @enum {string} + */ + readonly UndelegateSubmissionMethod: + | 'METHOD_UNSPECIFIED' + | 'METHOD_NOW' + | 'METHOD_AT_END_OF_EPOCH' + | 'METHOD_IN_ANGER'; + readonly blockexplorerapiv1Transaction: { + /** + * The height of the block the transaction was found in + * Format: uint64 + */ + readonly block?: string; + /** + * The results code of the transaction (0 is success) + * Format: int64 + */ + readonly code?: number; + /** The actual command of the transaction */ + readonly command?: components['schemas']['v1InputData']; + /** The cursor for this transaction (in the page, used for paginated results) */ + readonly cursor?: string; + /** The hash of the transaction */ + readonly hash?: string; + /** + * The index of the transaction in the block + * Format: int64 + */ + readonly index?: number; + /** The submitter of the transaction (Vega public key) */ + readonly submitter?: string; + /** The type of transaction */ + readonly type?: string; + }; + /** A transfer initiated by a party */ + readonly commandsv1Transfer: { + /** The amount to be taken from the source account */ + readonly amount?: string; + /** The asset */ + readonly asset?: string; + /** + * The account type from which the funds of the party + * should be taken + */ + readonly fromAccountType?: components['schemas']['vegaAccountType']; + readonly oneOff?: components['schemas']['v1OneOffTransfer']; + readonly recurring?: components['schemas']['v1RecurringTransfer']; + /** The reference to be attached to the transfer */ + readonly reference?: string; + /** The public key of the destination account */ + readonly to?: string; + /** The type of the destination account */ + readonly toAccountType?: components['schemas']['vegaAccountType']; + }; + readonly googlerpcStatus: { + /** Format: int32 */ + readonly code?: number; + readonly details?: readonly components['schemas']['protobufAny'][]; + readonly message?: string; + }; + readonly protobufAny: { + readonly '@type'?: string; + [key: string]: unknown | undefined; + }; + /** Used announce a node as a new potential validator */ + readonly v1AnnounceNode: { + /** AvatarURL of the validator */ + readonly avatarUrl?: string; + /** Public key for the blockchain, required field */ + readonly chainPubKey?: string; + /** Country code (ISO 3166-1 alpha-2) for the location of the node */ + readonly country?: string; + /** Ethereum public key, required field */ + readonly ethereumAddress?: string; + /** Signature from the validator made using the ethereum wallet */ + readonly ethereumSignature?: components['schemas']['v1Signature']; + /** + * The epoch from which the validator is expected + * to be ready to validate blocks + * Format: uint64 + */ + readonly fromEpoch?: string; + /** ID of the validator, (public master key) */ + readonly id?: string; + /** URL with more info on the node */ + readonly infoUrl?: string; + /** Name of the validator */ + readonly name?: string; + /** Ethereum public key to use as a submitter to allow automatic signature generation */ + readonly submitterAddress?: string; + /** Vega public key, required field */ + readonly vegaPubKey?: string; + /** + * Vega public key derivation index + * Format: int64 + */ + readonly vegaPubKeyIndex?: number; + /** Signature from the validator made using the vega wallet */ + readonly vegaSignature?: components['schemas']['v1Signature']; + }; + /** + * A batch of order instructions. + * This command accepts only the following batches of commands + * and will be processed in the following order: + * - OrderCancellation + * - OrderAmendment + * - OrderSubmission + * The total amount of commands in the batch across all three lists of + * instructions is restricted by the following network parameter: + * "spam.protection.max.batchSize" + */ + readonly v1BatchMarketInstructions: { + /** A list of order amendments to be processed sequentially */ + readonly amendments?: readonly components['schemas']['v1OrderAmendment'][]; + /** A list of order cancellations to be processed sequentially */ + readonly cancellations?: readonly components['schemas']['v1OrderCancellation'][]; + /** A list of order submissions to be processed sequentially */ + readonly submissions?: readonly components['schemas']['v1OrderSubmission'][]; + }; + /** A request for cancelling a recurring transfer */ + readonly v1CancelTransfer: { + /** The ID of the transfer to cancel */ + readonly transferId?: string; + }; + /** An event forwarded to the Vega network to provide information on events happening on other networks */ + readonly v1ChainEvent: { + /** Built-in asset event */ + readonly builtin?: components['schemas']['vegaBuiltinAssetEvent']; + /** Ethereum ERC20 event */ + readonly erc20?: components['schemas']['vegaERC20Event']; + /** Ethereum ERC20 multisig event */ + readonly erc20Multisig?: components['schemas']['vegaERC20MultiSigEvent']; + /** + * Arbitrary one-time integer used to prevent replay attacks + * Format: uint64 + */ + readonly nonce?: string; + /** Ethereum Staking event */ + readonly stakingEvent?: components['schemas']['vegaStakingEvent']; + /** The identifier of the transaction in which the events happened, usually a hash */ + readonly txId?: string; + }; + /** Condition describes the condition that must be validated by the network */ + readonly v1Condition: { + /** @description comparator is the type of comparison to make on the value. */ + readonly operator?: components['schemas']['ConditionOperator']; + /** @description value is used by the comparator. */ + readonly value?: string; + }; + /** A command to submit an instruction to delegate some stake to a node */ + readonly v1DelegateSubmission: { + /** The amount of stake to delegate */ + readonly amount?: string; + /** The ID for the node to delegate to */ + readonly nodeId?: string; + }; + readonly v1ETHAddress: { + readonly address?: string; + }; + /** A transaction to allow validator to rotate their ethereum keys */ + readonly v1EthereumKeyRotateSubmission: { + /** Currently used public address */ + readonly currentAddress?: string; + /** Signature that can be verified using the new ethereum address */ + readonly ethereumSignature?: components['schemas']['v1Signature']; + /** The new adress to rotate to */ + readonly newAddress?: string; + /** Ethereum public key to use as a submitter to allow automatic signature generation */ + readonly submitterAddress?: string; + /** + * Target block at which the key rotation will take effect on + * Format: uint64 + */ + readonly targetBlock?: string; + }; + /** + * @description Filter describes the conditions under which a data source data is considered of + * interest or not. + */ + readonly v1Filter: { + /** + * @description conditions are the conditions that should be matched by the data to be + * considered of interest. + */ + readonly conditions?: readonly components['schemas']['v1Condition'][]; + /** @description key is the data source data property key targeted by the filter. */ + readonly key?: components['schemas']['v1PropertyKey']; + }; + readonly v1GetTransactionResponse: { + /** The transaction corresponding to the hash */ + readonly transaction?: components['schemas']['blockexplorerapiv1Transaction']; + }; + readonly v1InputData: { + readonly announceNode?: components['schemas']['v1AnnounceNode']; + readonly batchMarketInstructions?: components['schemas']['v1BatchMarketInstructions']; + /** + * Format: uint64 + * @description The block height at which the transaction was made. + * This should be the current block height. The transaction will be valid + * from the block and up to the `tolerance` block height. + * Example: If the network has a tolerance of 150 blocks and `block_height` + * is set to `200`, then the transaction will be valid until block `350`. + * Note that a `block_height` that is ahead of the real block height will be + * rejected. The tolerance can be queried from the chain's network parameters. + * `block_height` prevents replay attacks in conjunction with `nonce` (see above). + */ + readonly blockHeight?: string; + readonly cancelTransfer?: components['schemas']['v1CancelTransfer']; + readonly chainEvent?: components['schemas']['v1ChainEvent']; + readonly delegateSubmission?: components['schemas']['v1DelegateSubmission']; + readonly ethereumKeyRotateSubmission?: components['schemas']['v1EthereumKeyRotateSubmission']; + readonly issueSignatures?: components['schemas']['v1IssueSignatures']; + readonly keyRotateSubmission?: components['schemas']['v1KeyRotateSubmission']; + readonly liquidityProvisionAmendment?: components['schemas']['v1LiquidityProvisionAmendment']; + readonly liquidityProvisionCancellation?: components['schemas']['v1LiquidityProvisionCancellation']; + readonly liquidityProvisionSubmission?: components['schemas']['v1LiquidityProvisionSubmission']; + readonly nodeSignature?: components['schemas']['v1NodeSignature']; + /** Validator commands */ + readonly nodeVote?: components['schemas']['v1NodeVote']; + /** + * Format: uint64 + * @description A number to provide uniqueness to prevent accidental replays and, + * in combination with `block_height`, deliberate attacks. + * A nonce provides uniqueness for otherwise identical transactions, + * ensuring that the transaction hash uniquely identifies a specific transaction. + * Granted all other fields are equal, the nonce can either be a counter + * or generated at random to submit multiple transactions within the same + * block (see below), without being identified as replays. + * Please note that Protocol Buffers do not have a canonical, unique encoding + * and therefore different libraries or binaries may encode the same message + * slightly differently, causing a different hash. + */ + readonly nonce?: string; + /** Oracles */ + readonly oracleDataSubmission?: components['schemas']['v1OracleDataSubmission']; + readonly orderAmendment?: components['schemas']['v1OrderAmendment']; + readonly orderCancellation?: components['schemas']['v1OrderCancellation']; + /** User commands */ + readonly orderSubmission?: components['schemas']['v1OrderSubmission']; + readonly proposalSubmission?: components['schemas']['v1ProposalSubmission']; + readonly protocolUpgradeProposal?: components['schemas']['v1ProtocolUpgradeProposal']; + readonly stateVariableProposal?: components['schemas']['v1StateVariableProposal']; + readonly transfer?: components['schemas']['commandsv1Transfer']; + readonly undelegateSubmission?: components['schemas']['v1UndelegateSubmission']; + readonly validatorHeartbeat?: components['schemas']['v1ValidatorHeartbeat']; + readonly voteSubmission?: components['schemas']['v1VoteSubmission']; + readonly withdrawSubmission?: components['schemas']['v1WithdrawSubmission']; + }; + readonly v1IssueSignatures: { + /** The kind of signatures to generate, namely for whether a signer is being added or removed */ + readonly kind?: components['schemas']['v1NodeSignatureKind']; + /** The ethereum address which will submit the signatures to the smart-contract */ + readonly submitter?: string; + /** The ID of the node that will be signed in or out of the smartcontract */ + readonly validatorNodeId?: string; + }; + /** A transaction to allow validator to rotate their vega keys */ + readonly v1KeyRotateSubmission: { + /** Hash of currently used public key */ + readonly currentPubKeyHash?: string; + /** The new public key to rotate to */ + readonly newPubKey?: string; + /** + * New Vega public key derivation index + * Format: int64 + */ + readonly newPubKeyIndex?: number; + /** + * Target block at which the key rotation will take effect on + * Format: uint64 + */ + readonly targetBlock?: string; + }; + /** Amend a liquidity provision request */ + readonly v1LiquidityProvisionAmendment: { + readonly buys?: readonly components['schemas']['vegaLiquidityOrder'][]; + /** From here at least one of the following is required to consider the command valid */ + readonly commitmentAmount?: string; + readonly fee?: string; + readonly marketId?: string; + readonly reference?: string; + readonly sells?: readonly components['schemas']['vegaLiquidityOrder'][]; + }; + /** Cancel a liquidity provision request */ + readonly v1LiquidityProvisionCancellation: { + readonly marketId?: string; + }; + /** A liquidity provision submitted for a given market */ + readonly v1LiquidityProvisionSubmission: { + /** A set of liquidity buy orders to meet the liquidity provision obligation */ + readonly buys?: readonly components['schemas']['vegaLiquidityOrder'][]; + /** Specified as a unitless number that represents the amount of settlement asset of the market */ + readonly commitmentAmount?: string; + /** Nominated liquidity fee factor, which is an input to the calculation of taker fees on the market, as per setting fees and rewarding liquidity providers */ + readonly fee?: string; + /** Market identifier for the order, required field */ + readonly marketId?: string; + /** A reference to be added to every order created out of this liquidityProvisionSubmission */ + readonly reference?: string; + /** A set of liquidity sell orders to meet the liquidity provision obligation */ + readonly sells?: readonly components['schemas']['vegaLiquidityOrder'][]; + }; + readonly v1ListTransactionsResponse: { + /** The transaction corresponding to the specific request and filters */ + readonly transactions?: readonly components['schemas']['blockexplorerapiv1Transaction'][]; + }; + /** Represents a signature from a validator, to be used by a foreign chain in order to recognise a decision taken by the Vega network */ + readonly v1NodeSignature: { + /** The identifier of the resource being signed */ + readonly id?: string; + /** The kind of resource being signed */ + readonly kind?: components['schemas']['v1NodeSignatureKind']; + /** + * The signature + * Format: byte + */ + readonly sig?: string; + }; + /** + * The kind of the signature created by a node, for example, allow-listing a new asset, withdrawal etc + * @description - NODE_SIGNATURE_KIND_UNSPECIFIED: Represents an unspecified or missing value from the input + * - NODE_SIGNATURE_KIND_ASSET_NEW: Represents a signature for a new asset allow-listing + * - NODE_SIGNATURE_KIND_ASSET_WITHDRAWAL: Represents a signature for an asset withdrawal + * - NODE_SIGNATURE_KIND_ERC20_MULTISIG_SIGNER_ADDED: Represents a signature for a new signer added to the erc20 multisig contract + * - NODE_SIGNATURE_KIND_ERC20_MULTISIG_SIGNER_REMOVED: Represents a signature for a signer removed from the erc20 multisig contract + * - NODE_SIGNATURE_KIND_ASSET_UPDATE: Represents a signature for an asset update allow-listing + * @default NODE_SIGNATURE_KIND_UNSPECIFIED + * @enum {string} + */ + readonly v1NodeSignatureKind: + | 'NODE_SIGNATURE_KIND_UNSPECIFIED' + | 'NODE_SIGNATURE_KIND_ASSET_NEW' + | 'NODE_SIGNATURE_KIND_ASSET_WITHDRAWAL' + | 'NODE_SIGNATURE_KIND_ERC20_MULTISIG_SIGNER_ADDED' + | 'NODE_SIGNATURE_KIND_ERC20_MULTISIG_SIGNER_REMOVED' + | 'NODE_SIGNATURE_KIND_ASSET_UPDATE'; + /** + * Used when a node votes for validating a given resource exists or is valid, + * for example, an ERC20 deposit is valid and exists on ethereum + */ + readonly v1NodeVote: { + /** Reference, required field */ + readonly reference?: string; + }; + /** Specific details for a one off transfer */ + readonly v1OneOffTransfer: { + /** + * A unix timestamp in second. Time at which the + * transfer should be delivered in the to account + * Format: int64 + */ + readonly deliverOn?: string; + }; + /** Command to submit new Oracle data from third party providers */ + readonly v1OracleDataSubmission: { + /** + * The data provided by the data source + * In the case of Open Oracle - it will be the entire object - it will contain messages, signatures and price data + * Format: byte + */ + readonly payload?: string; + /** + * @description The source from which the data is coming from. Must be base64 encoded. + * Oracle data a type of external data source data. + */ + readonly source?: components['schemas']['OracleDataSubmissionOracleSource']; + }; + /** An order amendment is a request to amend or update an existing order on Vega */ + readonly v1OrderAmendment: { + /** + * Amend the expiry time for the order, if the Timestamp value is set, otherwise expiry time will remain unchanged + * - See [`VegaTimeResponse`](#api.VegaTimeResponse).`timestamp` + * Format: int64 + */ + readonly expiresAt?: string; + /** Market identifier, this is required to find the order and will not be updated */ + readonly marketId?: string; + /** Order identifier, this is required to find the order and will not be updated, required field */ + readonly orderId?: string; + /** Amend the pegged order offset for the order */ + readonly peggedOffset?: string; + /** + * Amend the pegged order reference for the order + * - See [`PeggedReference`](#vega.PeggedReference) + */ + readonly peggedReference?: components['schemas']['vegaPeggedReference']; + /** Amend the price for the order, if the Price value is set, otherwise price will remain unchanged - See [`Price`](#vega.Price) */ + readonly price?: string; + /** + * Amend the size for the order by the delta specified: + * - To reduce the size from the current value set a negative integer value + * - To increase the size from the current value, set a positive integer value + * - To leave the size unchanged set a value of zero + * Format: int64 + */ + readonly sizeDelta?: string; + /** + * Amend the time in force for the order, set to TIME_IN_FORCE_UNSPECIFIED to remain unchanged + * - See [`TimeInForce`](#api.VegaTimeResponse).`timestamp` + */ + readonly timeInForce?: components['schemas']['OrderTimeInForce']; + }; + /** An order cancellation is a request to cancel an existing order on Vega */ + readonly v1OrderCancellation: { + /** Market identifier for the order, required field */ + readonly marketId?: string; + /** Unique identifier for the order (set by the system after consensus), required field */ + readonly orderId?: string; + }; + /** An order submission is a request to submit or create a new order on Vega */ + readonly v1OrderSubmission: { + /** + * Timestamp for when the order will expire, in nanoseconds since the epoch, + * required field only for `Order.TimeInForce`.TIME_IN_FORCE_GTT` + * - See `VegaTimeResponse`.`timestamp` + * Format: int64 + */ + readonly expiresAt?: string; + /** Market identifier for the order, required field */ + readonly marketId?: string; + /** + * Used to specify the details for a pegged order + * - See `PeggedOrder` + */ + readonly peggedOrder?: components['schemas']['vegaPeggedOrder']; + /** + * Price for the order, the price is an integer, for example `123456` is a correctly + * formatted price of `1.23456` assuming market configured to 5 decimal places, + * , required field for limit orders, however it is not required for market orders + */ + readonly price?: string; + /** + * Reference given for the order, this is typically used to retrieve an order submitted through consensus, currently + * set internally by the node to return a unique reference identifier for the order submission + */ + readonly reference?: string; + /** + * Side for the order, e.g. SIDE_BUY or SIDE_SELL, required field + * - See `Side` + */ + readonly side?: components['schemas']['vegaSide']; + /** + * Size for the order, for example, in a futures market the size equals the number of units, cannot be negative + * Format: uint64 + */ + readonly size?: string; + /** + * Time in force indicates how long an order will remain active before it is executed or expires, required field + * - See `Order.TimeInForce` + */ + readonly timeInForce?: components['schemas']['OrderTimeInForce']; + /** Type for the order, required field - See `Order.Type` */ + readonly type?: components['schemas']['vegaOrderType']; + }; + /** @description PropertyKey describes the property key contained in an data source data. */ + readonly v1PropertyKey: { + /** @description name is the name of the property. */ + readonly name?: string; + /** @description type is the type of the property. */ + readonly type?: components['schemas']['v1PropertyKeyType']; + }; + /** + * @description Type describes the type of properties that are supported by the data source + * engine. + * + * - TYPE_UNSPECIFIED: The default value. + * - TYPE_EMPTY: Any type. + * - TYPE_INTEGER: Integer type. + * - TYPE_STRING: String type. + * - TYPE_BOOLEAN: Boolean type. + * - TYPE_DECIMAL: Any floating point decimal type. + * - TYPE_TIMESTAMP: Timestamp date type. + * @default TYPE_UNSPECIFIED + * @enum {string} + */ + readonly v1PropertyKeyType: + | 'TYPE_UNSPECIFIED' + | 'TYPE_EMPTY' + | 'TYPE_INTEGER' + | 'TYPE_STRING' + | 'TYPE_BOOLEAN' + | 'TYPE_DECIMAL' + | 'TYPE_TIMESTAMP'; + /** + * A command to submit a new proposal for the + * Vega network governance + */ + readonly v1ProposalSubmission: { + /** @description The rationale behind a proposal. */ + readonly rationale?: components['schemas']['vegaProposalRationale']; + /** Proposal reference */ + readonly reference?: string; + /** Proposal configuration and the actual change that is meant to be executed when proposal is enacted */ + readonly terms?: components['schemas']['vegaProposalTerms']; + }; + readonly v1ProtocolUpgradeProposal: { + /** + * The block height at which to perform the upgrade + * Format: uint64 + */ + readonly upgradeBlockHeight?: string; + /** the release tag for the vega binary */ + readonly vegaReleaseTag?: string; + }; + /** + * @description PubKey is the public key that signed this data. + * Different public keys coming from different sources will be further separated. + */ + readonly v1PubKey: { + readonly key?: string; + }; + /** Specific details for a recurring transfer */ + readonly v1RecurringTransfer: { + /** optional parameter defining how a transfer is dispatched */ + readonly dispatchStrategy?: components['schemas']['vegaDispatchStrategy']; + /** + * The last epoch at which this transfer shall be paid + * Format: uint64 + */ + readonly endEpoch?: string; + /** factor needs to be > 0 */ + readonly factor?: string; + /** + * The first epoch from which this transfer shall be paid + * Format: uint64 + */ + readonly startEpoch?: string; + }; + /** + * @description A signature to authenticate a transaction and to be verified by the Vega + * network. + */ + readonly v1Signature: { + /** @description The algorithm used to create the signature. */ + readonly algo?: string; + /** @description The bytes of the signature (hex-encoded). */ + readonly value?: string; + /** + * Format: int64 + * @description The version of the signature used to create the signature. + */ + readonly version?: number; + }; + readonly v1Signer: { + /** in case of an open oracle - Ethereum address will be submitted */ + readonly ethAddress?: components['schemas']['v1ETHAddress']; + /** + * @description pubKeys is the list of authorized public keys that signed the data for this + * source. All the public keys in the data should be contained in these + * public keys. + */ + readonly pubKey?: components['schemas']['v1PubKey']; + }; + readonly v1StateVariableProposal: { + /** The state value proposal details */ + readonly proposal?: components['schemas']['vegaStateValueProposal']; + }; + readonly v1UndelegateSubmission: { + /** optional, if not specified = ALL */ + readonly amount?: string; + readonly method?: components['schemas']['UndelegateSubmissionMethod']; + readonly nodeId?: string; + }; + /** + * A message from a validator signaling they are still online and validating blocks + * or ready to validate block when they are till a potential validator + */ + readonly v1ValidatorHeartbeat: { + /** Signature from the validator made using the ethereum wallet */ + readonly ethereumSignature?: components['schemas']['v1Signature']; + /** the id of the node emitting the heartbeat */ + readonly nodeId?: string; + /** Signature from the validator made using the vega wallet */ + readonly vegaSignature?: components['schemas']['v1Signature']; + }; + /** + * @description A command to submit a new vote for a governance + * proposal. + */ + readonly v1VoteSubmission: { + /** @description The ID of the proposal to vote for. */ + readonly proposalId?: string; + /** The actual value of the vote */ + readonly value?: components['schemas']['vegaVoteValue']; + }; + /** Represents the submission request to withdraw funds for a party on Vega */ + readonly v1WithdrawSubmission: { + /** The amount to be withdrawn */ + readonly amount?: string; + /** The asset to be withdrawn */ + readonly asset?: string; + /** Foreign chain specifics */ + readonly ext?: components['schemas']['vegaWithdrawExt']; + }; + /** + * Various collateral/account types as used by Vega + * @description - ACCOUNT_TYPE_UNSPECIFIED: Default value + * - ACCOUNT_TYPE_INSURANCE: Insurance pool accounts contain insurance pool funds for a market + * - ACCOUNT_TYPE_SETTLEMENT: Settlement accounts exist only during settlement or mark-to-market + * - ACCOUNT_TYPE_MARGIN: Margin accounts contain funds set aside for the margin needed to support a party's open positions. + * Each party will have a margin account for each market they have traded in. + * The required initial margin is allocated to each market from your general account. + * Collateral in the margin account can't be withdrawn or used as margin on another market until + * it is released back to the general account. + * The Vega protocol uses an internal accounting system to segregate funds held as + * margin from other funds to ensure they are never lost or 'double spent' + * + * Margin account funds will vary as margin requirements on positions change + * - ACCOUNT_TYPE_GENERAL: General accounts contain the collateral for a party that is not otherwise allocated. A party will + * have multiple general accounts, one for each asset they want + * to trade with + * + * General accounts are where funds are initially deposited or withdrawn from, + * it is also the account where funds are taken to fulfil fees and initial margin requirements + * - ACCOUNT_TYPE_FEES_INFRASTRUCTURE: Infrastructure accounts contain fees earned by providing infrastructure on Vega + * - ACCOUNT_TYPE_FEES_LIQUIDITY: Liquidity accounts contain fees earned by providing liquidity on Vega markets + * - ACCOUNT_TYPE_FEES_MAKER: This account is created to hold fees earned by placing orders that sit on the book + * and are then matched with an incoming order to create a trade - These fees reward parties + * who provide the best priced liquidity that actually allows trading to take place + * - ACCOUNT_TYPE_BOND: This account is created to maintain liquidity providers funds commitments + * - ACCOUNT_TYPE_EXTERNAL: External account represents an external source (deposit/withdrawal) + * - ACCOUNT_TYPE_GLOBAL_INSURANCE: Global insurance account for the asset + * - ACCOUNT_TYPE_GLOBAL_REWARD: Global reward account for the asset + * - ACCOUNT_TYPE_PENDING_TRANSFERS: Per asset account used to store pending transfers (if any) + * - ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES: Per asset reward account for fees paid to makers + * - ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES: Per asset reward account for fees received by makers + * - ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES: Per asset reward account for fees received by liquidity providers + * - ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS: Per asset reward account for market proposers when the market goes above some trading threshold + * @default ACCOUNT_TYPE_UNSPECIFIED + * @enum {string} + */ + readonly vegaAccountType: + | 'ACCOUNT_TYPE_UNSPECIFIED' + | 'ACCOUNT_TYPE_INSURANCE' + | 'ACCOUNT_TYPE_SETTLEMENT' + | 'ACCOUNT_TYPE_MARGIN' + | 'ACCOUNT_TYPE_GENERAL' + | 'ACCOUNT_TYPE_FEES_INFRASTRUCTURE' + | 'ACCOUNT_TYPE_FEES_LIQUIDITY' + | 'ACCOUNT_TYPE_FEES_MAKER' + | 'ACCOUNT_TYPE_BOND' + | 'ACCOUNT_TYPE_EXTERNAL' + | 'ACCOUNT_TYPE_GLOBAL_INSURANCE' + | 'ACCOUNT_TYPE_GLOBAL_REWARD' + | 'ACCOUNT_TYPE_PENDING_TRANSFERS' + | 'ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES' + | 'ACCOUNT_TYPE_REWARD_MAKER_RECEIVED_FEES' + | 'ACCOUNT_TYPE_REWARD_LP_RECEIVED_FEES' + | 'ACCOUNT_TYPE_REWARD_MARKET_PROPOSERS'; + /** The Vega representation of an external asset */ + readonly vegaAssetDetails: { + /** A built-in asset */ + readonly builtinAsset?: components['schemas']['vegaBuiltinAsset']; + /** + * Number of decimal / precision handled by this asset + * Format: uint64 + */ + readonly decimals?: string; + /** An Ethereum ERC20 asset */ + readonly erc20?: components['schemas']['vegaERC20']; + /** Name of the asset (e.g: Great British Pound) */ + readonly name?: string; + /** The minimum economically meaningful amount in the asset */ + readonly quantum?: string; + /** Symbol of the asset (e.g: GBP) */ + readonly symbol?: string; + }; + /** @description The changes to apply on an existing asset. */ + readonly vegaAssetDetailsUpdate: { + /** An Ethereum ERC20 asset */ + readonly erc20?: components['schemas']['vegaERC20Update']; + /** The minimum economically meaningful amount in the asset */ + readonly quantum?: string; + }; + /** A Vega internal asset */ + readonly vegaBuiltinAsset: { + /** Maximum amount that can be requested by a party through the built-in asset faucet at a time */ + readonly maxFaucetAmountMint?: string; + }; + /** A deposit for a Vega built-in asset */ + readonly vegaBuiltinAssetDeposit: { + /** The amount to be deposited */ + readonly amount?: string; + /** A Vega party identifier (pub-key) */ + readonly partyId?: string; + /** A Vega network internal asset identifier */ + readonly vegaAssetId?: string; + }; + /** An event related to a Vega built-in asset */ + readonly vegaBuiltinAssetEvent: { + /** Built-in asset deposit */ + readonly deposit?: components['schemas']['vegaBuiltinAssetDeposit']; + /** Built-in asset withdrawal */ + readonly withdrawal?: components['schemas']['vegaBuiltinAssetWithdrawal']; + }; + /** A withdrawal for a Vega built-in asset */ + readonly vegaBuiltinAssetWithdrawal: { + /** The amount to be withdrawn */ + readonly amount?: string; + /** A Vega network party identifier (pub-key) */ + readonly partyId?: string; + /** A Vega network internal asset identifier */ + readonly vegaAssetId?: string; + }; + /** + * @description DataSourceDefinition represents the top level object that deals with data sources. + * DataSourceDefinition can be external or internal, with whatever number of data sources are defined + * for each type in the child objects below. + */ + readonly vegaDataSourceDefinition: { + readonly external?: components['schemas']['vegaDataSourceDefinitionExternal']; + readonly internal?: components['schemas']['vegaDataSourceDefinitionInternal']; + }; + /** + * @description DataSourceDefinitionExternal is the top level object used for all external data sources. + * It contains one of any of the defined `SourceType` variants. + */ + readonly vegaDataSourceDefinitionExternal: { + readonly oracle?: components['schemas']['vegaDataSourceSpecConfiguration']; + }; + /** + * @description DataSourceDefinitionInternal is the top level object used for all internal data sources. + * It contains one of any of the defined `SourceType` variants. + */ + readonly vegaDataSourceDefinitionInternal: { + readonly time?: components['schemas']['vegaDataSourceSpecConfigurationTime']; + }; + /** + * @description All types of external data sources use the same configuration set for meeting requirements + * in order for the data to be useful for Vega - valid signatures and matching filters. + */ + readonly vegaDataSourceSpecConfiguration: { + /** + * @description filters describes which source data are considered of interest or not for + * the product (or the risk model). + */ + readonly filters?: readonly components['schemas']['v1Filter'][]; + /** + * @description signers is the list of authorized signatures that signed the data for this + * source. All the signatures in the data source data should be contained in this + * external source. All the signatures in the data should be contained in this list. + */ + readonly signers?: readonly components['schemas']['v1Signer'][]; + }; + /** @description DataSourceSpecConfigurationTime is the internal data source used for emitting timestamps. */ + readonly vegaDataSourceSpecConfigurationTime: { + /** @description Conditions that the timestamps should meet in order to be considered. */ + readonly conditions?: readonly components['schemas']['v1Condition'][]; + }; + /** + * DataSourceSpecToFutureBinding describes which property of the data source data is to be + * used as settlement data and which to use as the trading terminated trigger + */ + readonly vegaDataSourceSpecToFutureBinding: { + /** + * @description settlement_data_property holds the name of the property in the source data + * that should be used as settlement data. + * If it is set to "prices.BTC.value", then the Future will use the value of + * this property as settlement data. + */ + readonly settlementDataProperty?: string; + /** the name of the property in the data source data that signals termination of trading */ + readonly tradingTerminationProperty?: string; + }; + /** + * - DISPATCH_METRIC_MAKER_FEES_PAID: Dispatch metric that is using the total maker fees paid in the market + * - DISPATCH_METRIC_MAKER_FEES_RECEIVED: Dispatch metric that is using the total maker fees received in the market + * - DISPATCH_METRIC_LP_FEES_RECEIVED: Dispatch metric that is using the total LP fees received in the market + * - DISPATCH_METRIC_MARKET_VALUE: Dispatch metric that is using total value of the market if above the required threshold and not paid given proposer bonus yet + * @default DISPATCH_METRIC_UNSPECIFIED + * @enum {string} + */ + readonly vegaDispatchMetric: + | 'DISPATCH_METRIC_UNSPECIFIED' + | 'DISPATCH_METRIC_MAKER_FEES_PAID' + | 'DISPATCH_METRIC_MAKER_FEES_RECEIVED' + | 'DISPATCH_METRIC_LP_FEES_RECEIVED' + | 'DISPATCH_METRIC_MARKET_VALUE'; + readonly vegaDispatchStrategy: { + /** The asset to use for metric */ + readonly assetForMetric?: string; + /** Optional markets in scope */ + readonly markets?: readonly string[]; + /** The metric to apply */ + readonly metric?: components['schemas']['vegaDispatchMetric']; + }; + /** An ERC20 token based asset, living on the ethereum network */ + readonly vegaERC20: { + /** The address of the contract for the token, on the ethereum network */ + readonly contractAddress?: string; + /** + * The lifetime limits deposit per address + * note: this is a temporary measure that can be changed by governance + */ + readonly lifetimeLimit?: string; + /** + * The maximum you can withdraw instantly. All withdrawals over the threshold will be delayed by the withdrawal delay. + * There’s no limit on the size of a withdrawal + * note: this is a temporary measure that can be changed by governance + */ + readonly withdrawThreshold?: string; + }; + /** An asset deny-listing for an ERC20 token */ + readonly vegaERC20AssetDelist: { + /** The Vega network internal identifier of the asset */ + readonly vegaAssetId?: string; + }; + readonly vegaERC20AssetLimitsUpdated: { + /** The updated lifetime limits */ + readonly lifetimeLimits?: string; + /** The Ethereum wallet that initiated the deposit */ + readonly sourceEthereumAddress?: string; + /** The Vega network internal identifier of the asset */ + readonly vegaAssetId?: string; + /** The updated withdraw threshold */ + readonly withdrawThreshold?: string; + }; + /** An asset allow-listing for an ERC20 token */ + readonly vegaERC20AssetList: { + /** The ethereum address of the asset */ + readonly assetSource?: string; + /** The Vega network internal identifier of the asset */ + readonly vegaAssetId?: string; + }; + /** An asset deposit for an ERC20 token */ + readonly vegaERC20Deposit: { + /** The amount to be deposited */ + readonly amount?: string; + /** The Ethereum wallet that initiated the deposit */ + readonly sourceEthereumAddress?: string; + /** The Vega party identifier (pub-key) which is the target of the deposit */ + readonly targetPartyId?: string; + /** The vega network internal identifier of the asset */ + readonly vegaAssetId?: string; + }; + /** An event related to an ERC20 token */ + readonly vegaERC20Event: { + /** De-list an ERC20 asset */ + readonly assetDelist?: components['schemas']['vegaERC20AssetDelist']; + /** Update an ERC20 asset */ + readonly assetLimitsUpdated?: components['schemas']['vegaERC20AssetLimitsUpdated']; + /** List an ERC20 asset */ + readonly assetList?: components['schemas']['vegaERC20AssetList']; + /** + * The block in which the transaction was added + * Format: uint64 + */ + readonly block?: string; + /** Bridge operations has been resumed */ + readonly bridgeResumed?: boolean; + /** Bridge operations has been stopped */ + readonly bridgeStopped?: boolean; + /** Deposit ERC20 asset */ + readonly deposit?: components['schemas']['vegaERC20Deposit']; + /** + * Index of the log in the transaction + * Format: uint64 + */ + readonly index?: string; + /** Withdraw ERC20 asset */ + readonly withdrawal?: components['schemas']['vegaERC20Withdrawal']; + }; + /** An event related to the ERC20 MultiSig */ + readonly vegaERC20MultiSigEvent: { + /** + * The block in which the transaction was added + * Format: uint64 + */ + readonly block?: string; + /** + * Index of the log in the transaction + * Format: uint64 + */ + readonly index?: string; + /** Add a signer to the erc20 bridge */ + readonly signerAdded?: components['schemas']['vegaERC20SignerAdded']; + /** Remove a signer from the erc20 bridge */ + readonly signerRemoved?: components['schemas']['vegaERC20SignerRemoved']; + /** Threshold set */ + readonly thresholdSet?: components['schemas']['vegaERC20ThresholdSet']; + }; + /** A new signer added to the ERC20 bridge */ + readonly vegaERC20SignerAdded: { + /** + * Format: int64 + * @description The time at which the block was produced + * will be used to inform the core at what time + * the stake was made unavailable. + */ + readonly blockTime?: string; + /** The ethereum address of the new signer */ + readonly newSigner?: string; + /** The nonce create by the vega network used for this new signer */ + readonly nonce?: string; + }; + /** A signer removed from the ERC20 bridge */ + readonly vegaERC20SignerRemoved: { + /** + * Format: int64 + * @description The time at which the block was produced + * will be used to inform the core at what time + * the stake was made unavailable. + */ + readonly blockTime?: string; + /** The nonce create by the vega network used for this old signer */ + readonly nonce?: string; + /** The ethereum address of the old signer */ + readonly oldSigner?: string; + }; + /** The threshold have been updated on the multisigcontrol */ + readonly vegaERC20ThresholdSet: { + /** + * Format: int64 + * @description The time at which the block was produced + * will be used to inform the core at what time + * the stake was made unavailable. + */ + readonly blockTime?: string; + /** + * The new threshold + * Format: int64 + */ + readonly newThreshold?: number; + /** The nonce create by the vega network */ + readonly nonce?: string; + }; + readonly vegaERC20Update: { + /** + * The lifetime limits deposit per address. + * This is will be interpreted against the asset decimals. + * note: this is a temporary measure that can be changed by governance + */ + readonly lifetimeLimit?: string; + /** + * The maximum you can withdraw instantly. All withdrawals over the threshold will be delayed by the withdrawal delay. + * There’s no limit on the size of a withdrawal + * note: this is a temporary measure that can be changed by governance + */ + readonly withdrawThreshold?: string; + }; + /** An asset withdrawal for an ERC20 token */ + readonly vegaERC20Withdrawal: { + /** The reference nonce used for the transaction */ + readonly referenceNonce?: string; + /** The target Ethereum wallet address */ + readonly targetEthereumAddress?: string; + /** The Vega network internal identifier of the asset */ + readonly vegaAssetId?: string; + }; + /** An extension of data required for the withdraw submissions */ + readonly vegaErc20WithdrawExt: { + /** The address into which the bridge will release the funds */ + readonly receiverAddress?: string; + }; + /** Future product configuration */ + readonly vegaFutureProduct: { + /** The binding between the data source spec and the settlement data */ + readonly dataSourceSpecBinding?: components['schemas']['vegaDataSourceSpecToFutureBinding']; + /** The data source spec describing the data source for settlement */ + readonly dataSourceSpecForSettlementData?: components['schemas']['vegaDataSourceDefinition']; + /** The external data source spec describing the data source of trading termination */ + readonly dataSourceSpecForTradingTermination?: components['schemas']['vegaDataSourceDefinition']; + /** Product quote name */ + readonly quoteName?: string; + /** Asset ID for the product's settlement asset */ + readonly settlementAsset?: string; + /** + * The number of decimal places implied by the settlement data (such as price) emitted by the settlement data source + * Format: int64 + */ + readonly settlementDataDecimals?: number; + }; + /** Instrument configuration */ + readonly vegaInstrumentConfiguration: { + /** Instrument code, human-readable shortcode used to describe the instrument */ + readonly code?: string; + /** Future */ + readonly future?: components['schemas']['vegaFutureProduct']; + /** Instrument name */ + readonly name?: string; + }; + readonly vegaKeyValueBundle: { + readonly key?: string; + readonly tolerance?: string; + readonly value?: components['schemas']['vegaStateVarValue']; + }; + /** LiquidityMonitoringParameters contains settings used for liquidity monitoring */ + readonly vegaLiquidityMonitoringParameters: { + /** + * Specifies by how many seconds an auction should be extended if leaving the auction were to trigger a liquidity auction + * Format: int64 + */ + readonly auctionExtension?: string; + /** Specifies parameters related to target stake calculation */ + readonly targetStakeParameters?: components['schemas']['vegaTargetStakeParameters']; + /** + * Specifies the triggering ratio for entering liquidity auction + * Format: double + */ + readonly triggeringRatio?: number; + }; + /** Represents a liquidity order */ + readonly vegaLiquidityOrder: { + /** The offset/amount of units away for the order */ + readonly offset?: string; + /** + * The relative proportion of the commitment to be allocated at a price level + * Format: int64 + */ + readonly proportion?: number; + /** The pegged reference point for the order */ + readonly reference?: components['schemas']['vegaPeggedReference']; + }; + /** Risk model parameters for log normal */ + readonly vegaLogNormalModelParams: { + /** + * Mu param + * Format: double + */ + readonly mu?: number; + /** + * R param + * Format: double + */ + readonly r?: number; + /** + * Sigma param + * Format: double + */ + readonly sigma?: number; + }; + /** Risk model for log normal */ + readonly vegaLogNormalRiskModel: { + /** Risk model parameters for log normal */ + readonly params?: components['schemas']['vegaLogNormalModelParams']; + /** + * Risk Aversion Parameter + * Format: double + */ + readonly riskAversionParameter?: number; + /** + * Tau + * Format: double + */ + readonly tau?: number; + }; + readonly vegaMatrixValue: { + readonly value?: readonly components['schemas']['vegaVectorValue'][]; + }; + /** Represents a network parameter on Vega */ + readonly vegaNetworkParameter: { + /** The unique key */ + readonly key?: string; + /** The value for the network parameter */ + readonly value?: string; + }; + /** New asset on Vega */ + readonly vegaNewAsset: { + /** The configuration of the new asset */ + readonly changes?: components['schemas']['vegaAssetDetails']; + }; + /** + * @description Freeform proposal + * This message is just used as a placeholder to sort out the nature of the + * proposal once parsed. + */ + readonly vegaNewFreeform: Record; + /** New market on Vega */ + readonly vegaNewMarket: { + /** The configuration of the new market */ + readonly changes?: components['schemas']['vegaNewMarketConfiguration']; + }; + /** Configuration for a new market on Vega */ + readonly vegaNewMarketConfiguration: { + /** + * Decimal places used for the new market, sets the smallest price increment on the book + * Format: uint64 + */ + readonly decimalPlaces?: string; + /** New market instrument configuration */ + readonly instrument?: components['schemas']['vegaInstrumentConfiguration']; + /** Liquidity monitoring parameters */ + readonly liquidityMonitoringParameters?: components['schemas']['vegaLiquidityMonitoringParameters']; + /** Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected */ + readonly logNormal?: components['schemas']['vegaLogNormalRiskModel']; + /** Optional new market meta data, tags */ + readonly metadata?: readonly string[]; + /** + * Decimal places for order sizes, sets what size the smallest order / position on the market can be + * Format: int64 + */ + readonly positionDecimalPlaces?: string; + /** Price monitoring parameters */ + readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters']; + /** Simple risk model parameters, valid only if MODEL_SIMPLE is selected */ + readonly simple?: components['schemas']['vegaSimpleModelParams']; + }; + /** + * Type values for an order + * @description - TYPE_UNSPECIFIED: Default value, always invalid + * - TYPE_LIMIT: Used for Limit orders + * - TYPE_MARKET: Used for Market orders + * - TYPE_NETWORK: Used for orders where the initiating party is the network (with distressed parties) + * @default TYPE_UNSPECIFIED + * @enum {string} + */ + readonly vegaOrderType: + | 'TYPE_UNSPECIFIED' + | 'TYPE_LIMIT' + | 'TYPE_MARKET' + | 'TYPE_NETWORK'; + /** + * Pegged orders are limit orders where the price is specified in the form REFERENCE +/- OFFSET + * They can be used for any limit order that is valid during continuous trading + */ + readonly vegaPeggedOrder: { + /** Offset from the price reference */ + readonly offset?: string; + /** The price point the order is linked to */ + readonly reference?: components['schemas']['vegaPeggedReference']; + }; + /** + * A pegged reference defines which price point a pegged order is linked to - meaning + * the price for a pegged order is calculated from the value of the reference price point + * @description - PEGGED_REFERENCE_UNSPECIFIED: Default value for PeggedReference, no reference given + * - PEGGED_REFERENCE_MID: Mid price reference + * - PEGGED_REFERENCE_BEST_BID: Best bid price reference + * - PEGGED_REFERENCE_BEST_ASK: Best ask price reference + * @default PEGGED_REFERENCE_UNSPECIFIED + * @enum {string} + */ + readonly vegaPeggedReference: + | 'PEGGED_REFERENCE_UNSPECIFIED' + | 'PEGGED_REFERENCE_MID' + | 'PEGGED_REFERENCE_BEST_BID' + | 'PEGGED_REFERENCE_BEST_ASK'; + /** PriceMonitoringParameters contains a collection of triggers to be used for a given market */ + readonly vegaPriceMonitoringParameters: { + readonly triggers?: readonly components['schemas']['vegaPriceMonitoringTrigger'][]; + }; + /** PriceMonitoringTrigger holds together price projection horizon τ, probability level p, and auction extension duration */ + readonly vegaPriceMonitoringTrigger: { + /** + * Price monitoring auction extension duration in seconds should the price + * breach it's theoretical level over the specified horizon at the specified + * probability level + * Format: int64 + */ + readonly auctionExtension?: string; + /** + * Price monitoring projection horizon τ in seconds + * Format: int64 + */ + readonly horizon?: string; + /** Price monitoring probability level p */ + readonly probability?: string; + }; + /** @description The rationale behind a proposal. */ + readonly vegaProposalRationale: { + /** + * @description Description to show a short title / something in case the link goes offline. + * This is to be between 0 and 20k unicode characters. + * This is mandatory for all proposals. + */ + readonly description?: string; + /** + * @description Title to be used to give a short description of the proposal in lists. + * This is to be between 0 and 100 unicode characters. + * This is mandatory for all proposals. + */ + readonly title?: string; + }; + /** Terms for a governance proposal on Vega */ + readonly vegaProposalTerms: { + /** + * Timestamp (Unix time in seconds) when voting closes for this proposal, + * constrained by `minClose` and `maxClose` network parameters + * Format: int64 + */ + readonly closingTimestamp?: string; + /** + * Timestamp (Unix time in seconds) when proposal gets enacted (if passed), + * constrained by `minEnact` and `maxEnact` network parameters + * Format: int64 + */ + readonly enactmentTimestamp?: string; + /** Proposal change for creating new assets on Vega */ + readonly newAsset?: components['schemas']['vegaNewAsset']; + /** + * Proposal change for a freeform request, which can be voted on but does not change the behaviour of the system, + * and can be used to gauge community sentiment + */ + readonly newFreeform?: components['schemas']['vegaNewFreeform']; + /** Proposal change for creating new market on Vega */ + readonly newMarket?: components['schemas']['vegaNewMarket']; + /** Proposal change for updating an asset */ + readonly updateAsset?: components['schemas']['vegaUpdateAsset']; + /** Proposal change for modifying an existing market on Vega */ + readonly updateMarket?: components['schemas']['vegaUpdateMarket']; + /** Proposal change for updating Vega network parameters */ + readonly updateNetworkParameter?: components['schemas']['vegaUpdateNetworkParameter']; + /** + * Validation timestamp (Unix time in seconds) + * Format: int64 + */ + readonly validationTimestamp?: string; + }; + readonly vegaScalarValue: { + readonly value?: string; + }; + /** + * A side relates to the direction of an order, to Buy, or Sell + * @description - SIDE_UNSPECIFIED: Default value, always invalid + * - SIDE_BUY: Buy order + * - SIDE_SELL: Sell order + * @default SIDE_UNSPECIFIED + * @enum {string} + */ + readonly vegaSide: 'SIDE_UNSPECIFIED' | 'SIDE_BUY' | 'SIDE_SELL'; + /** Risk model parameters for simple modelling */ + readonly vegaSimpleModelParams: { + /** + * Pre-defined risk factor value for long + * Format: double + */ + readonly factorLong?: number; + /** + * Pre-defined risk factor value for short + * Format: double + */ + readonly factorShort?: number; + /** + * Pre-defined maximum price move up that the model considers as valid + * Format: double + */ + readonly maxMoveUp?: number; + /** + * Pre-defined minimum price move down that the model considers as valid + * Format: double + */ + readonly minMoveDown?: number; + /** + * Pre-defined constant probability of trading + * Format: double + */ + readonly probabilityOfTrading?: number; + }; + readonly vegaStakeDeposited: { + /** The amount deposited (base 10) */ + readonly amount?: string; + /** + * Format: int64 + * @description The time at which the block was produced + * will be used to inform the core at what time + * the stake started to be available. + */ + readonly blockTime?: string; + /** Ethereum Address of the user depositing stake (hex encode with 0x prefix) */ + readonly ethereumAddress?: string; + /** The public of the party receiving the stake deposit (hex encode) */ + readonly vegaPublicKey?: string; + }; + readonly vegaStakeRemoved: { + /** The amount removed (base 10) */ + readonly amount?: string; + /** + * Format: int64 + * @description The time at which the block was produced + * will be used to inform the core at what time + * the stake was made unavailable. + */ + readonly blockTime?: string; + /** Ethereum address of the user removing stake (hex encode with 0x prefix) */ + readonly ethereumAddress?: string; + /** The public key of the party from which to remove stake (hex encode) */ + readonly vegaPublicKey?: string; + }; + readonly vegaStakeTotalSupply: { + /** The address of the staking asset */ + readonly tokenAddress?: string; + /** The total supply observed for the token */ + readonly totalSupply?: string; + }; + readonly vegaStakingEvent: { + /** + * The block in which the transaction was added + * Format: uint64 + */ + readonly block?: string; + /** + * Index of the log in the transaction + * Format: uint64 + */ + readonly index?: string; + readonly stakeDeposited?: components['schemas']['vegaStakeDeposited']; + readonly stakeRemoved?: components['schemas']['vegaStakeRemoved']; + readonly totalSupply?: components['schemas']['vegaStakeTotalSupply']; + }; + readonly vegaStateValueProposal: { + /** event identifier */ + readonly eventId?: string; + /** key value tolerance triplets */ + readonly kvb?: readonly components['schemas']['vegaKeyValueBundle'][]; + /** state variable identifier */ + readonly stateVarId?: string; + }; + readonly vegaStateVarValue: { + readonly matrixVal?: components['schemas']['vegaMatrixValue']; + readonly scalarVal?: components['schemas']['vegaScalarValue']; + readonly vectorVal?: components['schemas']['vegaVectorValue']; + }; + /** TargetStakeParameters contains parameters used in target stake calculation */ + readonly vegaTargetStakeParameters: { + /** + * Specifies scaling factors used in target stake calculation + * Format: double + */ + readonly scalingFactor?: number; + /** + * Specifies length of time window expressed in seconds for target stake calculation + * Format: int64 + */ + readonly timeWindow?: string; + }; + /** Update an existing asset on Vega */ + readonly vegaUpdateAsset: { + /** The ID of the asset to be updated */ + readonly assetId?: string; + /** The changes to apply on an existing asset */ + readonly changes?: components['schemas']['vegaAssetDetailsUpdate']; + }; + /** Future product configuration */ + readonly vegaUpdateFutureProduct: { + /** The binding between the data source spec and the settlement data */ + readonly dataSourceSpecBinding?: components['schemas']['vegaDataSourceSpecToFutureBinding']; + /** The data source spec describing the data of settlement data */ + readonly dataSourceSpecForSettlementData?: components['schemas']['vegaDataSourceDefinition']; + /** The data source spec describing the data source for trading termination */ + readonly dataSourceSpecForTradingTermination?: components['schemas']['vegaDataSourceDefinition']; + /** Human-readable name/abbreviation of the quote name */ + readonly quoteName?: string; + /** + * The number of decimal places implied by the settlement data (such as price) emitted by the settlement external data source + * Format: int64 + */ + readonly settlementDataDecimals?: number; + }; + /** Instrument configuration */ + readonly vegaUpdateInstrumentConfiguration: { + /** Instrument code, human-readable shortcode used to describe the instrument */ + readonly code?: string; + /** Future */ + readonly future?: components['schemas']['vegaUpdateFutureProduct']; + }; + /** Update an existing market on Vega */ + readonly vegaUpdateMarket: { + /** The updated configuration of the market */ + readonly changes?: components['schemas']['vegaUpdateMarketConfiguration']; + /** The identifier of the market to update */ + readonly marketId?: string; + }; + /** Configuration to update a market on Vega */ + readonly vegaUpdateMarketConfiguration: { + /** Updated market instrument configuration */ + readonly instrument?: components['schemas']['vegaUpdateInstrumentConfiguration']; + /** Liquidity monitoring parameters */ + readonly liquidityMonitoringParameters?: components['schemas']['vegaLiquidityMonitoringParameters']; + /** Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected */ + readonly logNormal?: components['schemas']['vegaLogNormalRiskModel']; + /** Optional market metadata, tags */ + readonly metadata?: readonly string[]; + /** Price monitoring parameters */ + readonly priceMonitoringParameters?: components['schemas']['vegaPriceMonitoringParameters']; + /** Simple risk model parameters, valid only if MODEL_SIMPLE is selected */ + readonly simple?: components['schemas']['vegaSimpleModelParams']; + }; + /** Update network configuration on Vega */ + readonly vegaUpdateNetworkParameter: { + /** The network parameter to update */ + readonly changes?: components['schemas']['vegaNetworkParameter']; + }; + readonly vegaVectorValue: { + readonly value?: readonly string[]; + }; + /** + * Vote value + * @description - VALUE_UNSPECIFIED: Default value, always invalid + * - VALUE_NO: A vote against the proposal + * - VALUE_YES: A vote in favour of the proposal + * @default VALUE_UNSPECIFIED + * @enum {string} + */ + readonly vegaVoteValue: 'VALUE_UNSPECIFIED' | 'VALUE_NO' | 'VALUE_YES'; + /** Withdrawal external details */ + readonly vegaWithdrawExt: { + /** ERC20 withdrawal details */ + readonly erc20?: components['schemas']['vegaErc20WithdrawExt']; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} + +export type external = Record; + +export interface operations { + BlockExplorer_ListTransactions: { + /** + * List transactions + * @description List transactions from the Vega blockchain + */ + parameters?: { + /** @description The number of transactions to be returned from the blockchain. */ + /** @description An optional cursor to paginate the request. */ + /** @description An optional cursor to paginate the request. */ + readonly query?: { + limit?: number; + before?: string; + after?: string; + }; + }; + responses: { + /** @description A successful response. */ + 200: { + content: { + readonly 'application/json': components['schemas']['v1ListTransactionsResponse']; + }; + }; + /** @description An unexpected error response. */ + default: { + content: { + readonly 'application/json': components['schemas']['googlerpcStatus']; + }; + }; + }; + }; + BlockExplorer_GetTransaction: { + /** + * Get transaction + * @description Get a transaction from the Vega blockchain + */ + parameters: { + /** @description The hash of the transaction */ + readonly path: { + hash: string; + }; + }; + responses: { + /** @description A successful response. */ + 200: { + content: { + readonly 'application/json': components['schemas']['v1GetTransactionResponse']; + }; + }; + /** @description An unexpected error response. */ + default: { + content: { + readonly 'application/json': components['schemas']['googlerpcStatus']; + }; + }; + }; + }; +} diff --git a/apps/explorer/tsconfig.json b/apps/explorer/tsconfig.json index 274e1b190..9ec83e76b 100644 --- a/apps/explorer/tsconfig.json +++ b/apps/explorer/tsconfig.json @@ -13,6 +13,7 @@ "noFallthroughCasesInSwitch": true, "lib": ["es5", "es6", "dom", "dom.iterable"] }, + "exclude": ["./src/types/explorer.d.ts"], "include": [], "references": [ {