add block explorer
This commit is contained in:
parent
726bcaf579
commit
b41b97556f
25
apps/block-explorer/.env
Normal file
25
apps/block-explorer/.env
Normal file
@ -0,0 +1,25 @@
|
||||
# React Environment Variables
|
||||
# https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#expanding-environment-variables-in-env
|
||||
|
||||
# Netlify Environment Variables
|
||||
# https://www.netlify.com/docs/continuous-deployment/#environment-variables
|
||||
REACT_APP_VERSION=$npm_package_version
|
||||
REACT_APP_REPOSITORY_URL=$REPOSITORY_URL
|
||||
REACT_APP_BRANCH=$BRANCH
|
||||
REACT_APP_PULL_REQUEST=$PULL_REQUEST
|
||||
REACT_APP_HEAD=$HEAD
|
||||
REACT_APP_COMMIT_REF=$COMMIT_REF
|
||||
REACT_APP_CONTEXT=$CONTEXT
|
||||
REACT_APP_REVIEW_ID=$REVIEW_ID
|
||||
REACT_APP_INCOMING_HOOK_TITLE=$INCOMING_HOOK_TITLE
|
||||
REACT_APP_INCOMING_HOOK_URL=$INCOMING_HOOK_URL
|
||||
REACT_APP_INCOMING_HOOK_BODY=$INCOMING_HOOK_BODY
|
||||
REACT_APP_URL=$URL
|
||||
REACT_APP_DEPLOY_URL=$DEPLOY_URL
|
||||
REACT_APP_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
|
||||
|
||||
# App configuration variables
|
||||
REACT_APP_CHAIN_EXPLORER_URL = "https://explorer.vega.trading/.netlify/functions/chain-explorer-api"
|
||||
REACT_APP_TENDERMINT_URL = "https://lb.testnet.vega.xyz/tm"
|
||||
REACT_APP_TENDERMINT_WEBSOCKET_URL = "wss://lb.testnet.vega.xyz/tm/websocket"
|
||||
REACT_APP_VEGA_URL = "https://lb.testnet.vega.xyz/query"
|
23
apps/block-explorer/.gitignore
vendored
Normal file
23
apps/block-explorer/.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
46
apps/block-explorer/README.md
Normal file
46
apps/block-explorer/README.md
Normal file
@ -0,0 +1,46 @@
|
||||
# Getting Started with Create React App
|
||||
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm start`
|
||||
|
||||
Runs the app in the development mode.\
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
|
||||
|
||||
The page will reload if you make edits.\
|
||||
You will also see any lint errors in the console.
|
||||
|
||||
### `npm test`
|
||||
|
||||
Launches the test runner in the interactive watch mode.\
|
||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Builds the app for production to the `build` folder.\
|
||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.\
|
||||
Your app is ready to be deployed!
|
||||
|
||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||
|
||||
### `npm run eject`
|
||||
|
||||
**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
|
||||
|
||||
If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||
|
||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
|
||||
|
||||
You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
|
||||
|
||||
## Learn More
|
||||
|
||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||
|
||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
8
apps/block-explorer/apollo.config.js
Normal file
8
apps/block-explorer/apollo.config.js
Normal file
@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
client: {
|
||||
service: {
|
||||
name: "vega",
|
||||
url: process.env.REACT_APP_VEGA_URL,
|
||||
},
|
||||
},
|
||||
};
|
4
apps/block-explorer/netlify.toml
Normal file
4
apps/block-explorer/netlify.toml
Normal file
@ -0,0 +1,4 @@
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
57
apps/block-explorer/package.json
Normal file
57
apps/block-explorer/package.json
Normal file
@ -0,0 +1,57 @@
|
||||
{
|
||||
"name": "vega-explorer",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.5.8",
|
||||
"@testing-library/jest-dom": "^5.16.2",
|
||||
"@testing-library/react": "^12.1.2",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/node": "^16.11.22",
|
||||
"@types/react": "^17.0.39",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"graphql": "^15.7.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-router-dom": "^5.2.1",
|
||||
"react-scripts": "5.0.0",
|
||||
"react-use-websocket": "^3.0.0",
|
||||
"sass": "^1.49.7",
|
||||
"typescript": "^4.5.5",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"generate": "env-cmd yarn apollo codegen:generate --target=typescript --globalTypesFile=src/__generated__/globalTypes.ts"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"apollo": "^2.33.9",
|
||||
"env-cmd": "^10.1.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"graphql": "15.8.0"
|
||||
}
|
||||
}
|
BIN
apps/block-explorer/public/favicon.ico
Normal file
BIN
apps/block-explorer/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
43
apps/block-explorer/public/index.html
Normal file
43
apps/block-explorer/public/index.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
BIN
apps/block-explorer/public/logo192.png
Normal file
BIN
apps/block-explorer/public/logo192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
apps/block-explorer/public/logo512.png
Normal file
BIN
apps/block-explorer/public/logo512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
25
apps/block-explorer/public/manifest.json
Normal file
25
apps/block-explorer/public/manifest.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
3
apps/block-explorer/public/robots.txt
Normal file
3
apps/block-explorer/public/robots.txt
Normal file
@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
73
apps/block-explorer/src/App.scss
Normal file
73
apps/block-explorer/src/App.scss
Normal file
@ -0,0 +1,73 @@
|
||||
@import "./styles/colors";
|
||||
@import "./styles/fonts";
|
||||
@import "./styles/reset";
|
||||
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
background-color: $black;
|
||||
color: $white;
|
||||
font-family: $font-main;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.app {
|
||||
max-width: 1300px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-rows: 1fr min-content;
|
||||
min-height: 100%;
|
||||
|
||||
@media (min-width: 960px) {
|
||||
border-left: 1px solid $white;
|
||||
border-right: 1px solid $white;
|
||||
}
|
||||
}
|
||||
|
||||
.template-sidebar {
|
||||
border-bottom: 1px solid $white;
|
||||
border-top: 1px solid $white;
|
||||
display: grid;
|
||||
grid-template-rows: auto minmax(700px, 1fr);
|
||||
grid-template-columns: 300px minmax(auto, 1fr);
|
||||
|
||||
nav {
|
||||
border-right: 1px solid $white;
|
||||
padding: 20px;
|
||||
grid-column-start: 1;
|
||||
grid-column-end: 1;
|
||||
grid-row-start: 1;
|
||||
grid-row-end: 3;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid $white;
|
||||
grid-column-start: 2;
|
||||
grid-column-end: 2;
|
||||
grid-row-start: 1;
|
||||
grid-row-end: 2;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 20px;
|
||||
grid-column-start: 2;
|
||||
grid-column-end: 2;
|
||||
grid-row-start: 2;
|
||||
grid-row-end: 3;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
footer {
|
||||
border-top: 1px solid $white;
|
||||
padding: 20px;
|
||||
grid-column-start: 1;
|
||||
grid-column-end: 3;
|
||||
grid-row-start: 3;
|
||||
grid-row-end: 4;
|
||||
}
|
||||
}
|
9
apps/block-explorer/src/App.test.tsx
Normal file
9
apps/block-explorer/src/App.test.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
35
apps/block-explorer/src/App.tsx
Normal file
35
apps/block-explorer/src/App.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import "./App.scss";
|
||||
|
||||
import { ApolloProvider } from "@apollo/client";
|
||||
|
||||
import { createClient } from "./lib/apollo-client";
|
||||
import { BrowserRouter as Router } from "react-router-dom";
|
||||
import { Nav } from "./components/nav";
|
||||
import { Footer } from "./components/footer";
|
||||
import { Header } from "./components/header";
|
||||
import { Main } from "./components/main";
|
||||
import React from "react";
|
||||
import { DATA_SOURCES } from "./config";
|
||||
import { TendermintWebsocketProvider } from "./contexts/websocket/tendermint-websocket-provider";
|
||||
|
||||
function App() {
|
||||
const [client] = React.useState(createClient(DATA_SOURCES.dataNodeUrl));
|
||||
return (
|
||||
<Router>
|
||||
<TendermintWebsocketProvider>
|
||||
<ApolloProvider client={client}>
|
||||
<div className="app">
|
||||
<div className="template-sidebar">
|
||||
<Nav />
|
||||
<Header />
|
||||
<Main />
|
||||
<Footer />
|
||||
</div>
|
||||
</div>
|
||||
</ApolloProvider>
|
||||
</TendermintWebsocketProvider>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
126
apps/block-explorer/src/__generated__/globalTypes.ts
generated
Normal file
126
apps/block-explorer/src/__generated__/globalTypes.ts
generated
Normal file
@ -0,0 +1,126 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
//==============================================================
|
||||
// START Enums and Input Objects
|
||||
//==============================================================
|
||||
|
||||
/**
|
||||
* The various account types we have (used by collateral)
|
||||
*/
|
||||
export enum AccountType {
|
||||
Bond = "Bond",
|
||||
FeeInfrastructure = "FeeInfrastructure",
|
||||
FeeLiquidity = "FeeLiquidity",
|
||||
General = "General",
|
||||
GlobalInsurance = "GlobalInsurance",
|
||||
Insurance = "Insurance",
|
||||
LockWithdraw = "LockWithdraw",
|
||||
Margin = "Margin",
|
||||
Settlement = "Settlement",
|
||||
}
|
||||
|
||||
export enum AuctionTrigger {
|
||||
Batch = "Batch",
|
||||
Liquidity = "Liquidity",
|
||||
Opening = "Opening",
|
||||
Price = "Price",
|
||||
Unspecified = "Unspecified",
|
||||
}
|
||||
|
||||
/**
|
||||
* The current state of a market
|
||||
*/
|
||||
export enum MarketState {
|
||||
Active = "Active",
|
||||
Cancelled = "Cancelled",
|
||||
Closed = "Closed",
|
||||
Pending = "Pending",
|
||||
Proposed = "Proposed",
|
||||
Rejected = "Rejected",
|
||||
Settled = "Settled",
|
||||
Suspended = "Suspended",
|
||||
TradingTerminated = "TradingTerminated",
|
||||
}
|
||||
|
||||
/**
|
||||
* What market trading mode are we in
|
||||
*/
|
||||
export enum MarketTradingMode {
|
||||
BatchAuction = "BatchAuction",
|
||||
Continuous = "Continuous",
|
||||
MonitoringAuction = "MonitoringAuction",
|
||||
OpeningAuction = "OpeningAuction",
|
||||
}
|
||||
|
||||
export enum NodeStatus {
|
||||
NonValidator = "NonValidator",
|
||||
Validator = "Validator",
|
||||
}
|
||||
|
||||
/**
|
||||
* Reason for the proposal being rejected by the core node
|
||||
*/
|
||||
export enum ProposalRejectionReason {
|
||||
CloseTimeTooLate = "CloseTimeTooLate",
|
||||
CloseTimeTooSoon = "CloseTimeTooSoon",
|
||||
CouldNotInstantiateMarket = "CouldNotInstantiateMarket",
|
||||
EnactTimeTooLate = "EnactTimeTooLate",
|
||||
EnactTimeTooSoon = "EnactTimeTooSoon",
|
||||
IncompatibleTimestamps = "IncompatibleTimestamps",
|
||||
InsufficientTokens = "InsufficientTokens",
|
||||
InvalidAsset = "InvalidAsset",
|
||||
InvalidAssetDetails = "InvalidAssetDetails",
|
||||
InvalidFeeAmount = "InvalidFeeAmount",
|
||||
InvalidFutureMaturityTimestamp = "InvalidFutureMaturityTimestamp",
|
||||
InvalidFutureProduct = "InvalidFutureProduct",
|
||||
InvalidInstrumentSecurity = "InvalidInstrumentSecurity",
|
||||
InvalidRiskParameter = "InvalidRiskParameter",
|
||||
InvalidShape = "InvalidShape",
|
||||
MajorityThresholdNotReached = "MajorityThresholdNotReached",
|
||||
MarketMissingLiquidityCommitment = "MarketMissingLiquidityCommitment",
|
||||
MissingBuiltinAssetField = "MissingBuiltinAssetField",
|
||||
MissingCommitmentAmount = "MissingCommitmentAmount",
|
||||
MissingERC20ContractAddress = "MissingERC20ContractAddress",
|
||||
NetworkParameterInvalidKey = "NetworkParameterInvalidKey",
|
||||
NetworkParameterInvalidValue = "NetworkParameterInvalidValue",
|
||||
NetworkParameterValidationFailed = "NetworkParameterValidationFailed",
|
||||
NoProduct = "NoProduct",
|
||||
NoRiskParameters = "NoRiskParameters",
|
||||
NoTradingMode = "NoTradingMode",
|
||||
NodeValidationFailed = "NodeValidationFailed",
|
||||
OpeningAuctionDurationTooLarge = "OpeningAuctionDurationTooLarge",
|
||||
OpeningAuctionDurationTooSmall = "OpeningAuctionDurationTooSmall",
|
||||
ParticipationThresholdNotReached = "ParticipationThresholdNotReached",
|
||||
ProductMaturityIsPassed = "ProductMaturityIsPassed",
|
||||
UnsupportedProduct = "UnsupportedProduct",
|
||||
UnsupportedTradingMode = "UnsupportedTradingMode",
|
||||
}
|
||||
|
||||
/**
|
||||
* Various states a proposal can transition through:
|
||||
* Open ->
|
||||
* - Passed -> Enacted.
|
||||
* - Rejected.
|
||||
* Proposal can enter Failed state from any other state.
|
||||
*/
|
||||
export enum ProposalState {
|
||||
Declined = "Declined",
|
||||
Enacted = "Enacted",
|
||||
Failed = "Failed",
|
||||
Open = "Open",
|
||||
Passed = "Passed",
|
||||
Rejected = "Rejected",
|
||||
WaitingForNodeVote = "WaitingForNodeVote",
|
||||
}
|
||||
|
||||
export enum VoteValue {
|
||||
No = "No",
|
||||
Yes = "Yes",
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
// END Enums and Input Objects
|
||||
//==============================================================
|
15
apps/block-explorer/src/components/footer/index.tsx
Normal file
15
apps/block-explorer/src/components/footer/index.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import packageJson from "../../../package.json";
|
||||
|
||||
export const Footer = () => {
|
||||
return (
|
||||
<footer>
|
||||
<section>
|
||||
<div>Reading Vega Fairground data from </div>
|
||||
<div>
|
||||
Version/commit hash: {packageJson.version} /
|
||||
{process.env.REACT_APP_COMMIT_REF || "dev"}
|
||||
</div>
|
||||
</section>
|
||||
</footer>
|
||||
);
|
||||
};
|
9
apps/block-explorer/src/components/header/index.tsx
Normal file
9
apps/block-explorer/src/components/header/index.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import Search from "../search";
|
||||
|
||||
export const Header = () => {
|
||||
return (
|
||||
<header>
|
||||
<Search />
|
||||
</header>
|
||||
);
|
||||
};
|
9
apps/block-explorer/src/components/main/index.tsx
Normal file
9
apps/block-explorer/src/components/main/index.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import { AppRouter } from "../../routes";
|
||||
|
||||
export const Main = () => {
|
||||
return (
|
||||
<main>
|
||||
<AppRouter />
|
||||
</main>
|
||||
);
|
||||
};
|
15
apps/block-explorer/src/components/nav/index.tsx
Normal file
15
apps/block-explorer/src/components/nav/index.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import { Link } from "react-router-dom";
|
||||
import routerConfig from "../../routes/router-config";
|
||||
|
||||
export const Nav = () => {
|
||||
return (
|
||||
<nav>
|
||||
{routerConfig.map((r) => (
|
||||
<div key={r.name}>
|
||||
<Link to={r.path}>{r.name}</Link>
|
||||
<br />
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
);
|
||||
};
|
@ -0,0 +1,31 @@
|
||||
import React from "react";
|
||||
|
||||
interface RouteErrorBoundaryProps {
|
||||
children: React.ReactElement;
|
||||
}
|
||||
|
||||
export class RouteErrorBoundary extends React.Component<
|
||||
RouteErrorBoundaryProps,
|
||||
{ hasError: boolean }
|
||||
> {
|
||||
constructor(props: RouteErrorBoundaryProps) {
|
||||
super(props);
|
||||
this.state = { hasError: false };
|
||||
}
|
||||
|
||||
static getDerivedStateFromError() {
|
||||
return { hasError: true };
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error) {
|
||||
console.log(`Error caught in App error boundary ${error.message}`, error);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return <h1>Something went wrong</h1>;
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
68
apps/block-explorer/src/components/search/index.tsx
Normal file
68
apps/block-explorer/src/components/search/index.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import React from "react";
|
||||
import { useState } from "react";
|
||||
|
||||
const PARTY_ID_LENGTH = 64;
|
||||
|
||||
enum PossibleIdTypes {
|
||||
Block = "Block",
|
||||
Tx = "Tx",
|
||||
Party = "Party",
|
||||
Unknown = "Unknown",
|
||||
}
|
||||
|
||||
const useGuess = () => {
|
||||
const [search, setSearch] = useState<string>("");
|
||||
const [possibleTypes, setPossibleTypes] = useState<PossibleIdTypes[]>();
|
||||
|
||||
const getPossibleIds = React.useCallback((search: string) => {
|
||||
if (!search.length) {
|
||||
return [];
|
||||
} else if (
|
||||
search.startsWith("0x") &&
|
||||
search.length === PARTY_ID_LENGTH + 2
|
||||
) {
|
||||
return [PossibleIdTypes.Tx, PossibleIdTypes.Party];
|
||||
} else if (!search.startsWith("0x") && search.length === PARTY_ID_LENGTH) {
|
||||
return [PossibleIdTypes.Tx, PossibleIdTypes.Party];
|
||||
} else if (!isNaN(Number(search))) {
|
||||
return [PossibleIdTypes.Block];
|
||||
}
|
||||
return [];
|
||||
}, []);
|
||||
|
||||
const onChange = React.useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const search = event.target.value;
|
||||
setSearch(search);
|
||||
setPossibleTypes(getPossibleIds(search));
|
||||
},
|
||||
[getPossibleIds]
|
||||
);
|
||||
|
||||
return {
|
||||
onChange,
|
||||
possibleTypes,
|
||||
search,
|
||||
};
|
||||
};
|
||||
|
||||
const Search = () => {
|
||||
const { search, onChange, possibleTypes } = useGuess();
|
||||
return (
|
||||
<section>
|
||||
<h1>Vega Block Explorer</h1>
|
||||
<fieldset>
|
||||
<label htmlFor="search">Search: </label>
|
||||
<input
|
||||
name="search"
|
||||
value={search}
|
||||
onChange={(e) => onChange(e)}
|
||||
></input>
|
||||
</fieldset>
|
||||
{/* TODO implement links */}
|
||||
<div>{JSON.stringify(possibleTypes)}</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Search;
|
@ -0,0 +1 @@
|
||||
export * from "./splash-loader";
|
@ -0,0 +1,22 @@
|
||||
@import "../../styles/colors";
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
&__animation {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
div {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: white;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
import "./splash-loader.scss";
|
||||
|
||||
import React from "react";
|
||||
|
||||
export const SplashLoader = ({ text = "Loading" }: { text?: string }) => {
|
||||
const [, forceRender] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
forceRender((x) => !x);
|
||||
}, 100);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="loading" data-testid="splash-loader">
|
||||
<div className="loading__animation">
|
||||
{new Array(25).fill(null).map((_, i) => {
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
style={{
|
||||
opacity: Math.random() > 0.75 ? 1 : 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div>{text}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1 @@
|
||||
export * from "./splash-screen";
|
@ -0,0 +1,12 @@
|
||||
@import "../../styles/colors";
|
||||
|
||||
.splash-screen {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 20px;
|
||||
color: $white;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
import "./splash-screen.scss";
|
||||
|
||||
import React from "react";
|
||||
|
||||
export const SplashScreen = ({ children }: { children: React.ReactNode }) => {
|
||||
return <div className="splash-screen">{children}</div>;
|
||||
};
|
7
apps/block-explorer/src/config/index.tsx
Normal file
7
apps/block-explorer/src/config/index.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
export const DATA_SOURCES = {
|
||||
chainExplorerUrl: process.env.REACT_APP_CHAIN_EXPLORER_URL as string,
|
||||
tendermintUrl: process.env.REACT_APP_TENDERMINT_URL as string,
|
||||
tendermintWebsocketUrl: process.env
|
||||
.REACT_APP_TENDERMINT_WEBSOCKET_URL as string,
|
||||
dataNodeUrl: process.env.REACT_APP_VEGA_URL as string,
|
||||
};
|
@ -0,0 +1,15 @@
|
||||
import React from "react";
|
||||
import { WebSocketHook } from "react-use-websocket/dist/lib/types";
|
||||
|
||||
export type WebsocketContextShape = WebSocketHook;
|
||||
|
||||
export const TendermintWebsocketContext =
|
||||
React.createContext<WebsocketContextShape | null>(null);
|
||||
|
||||
export function useTendermintWebsocketContext() {
|
||||
const context = React.useContext(TendermintWebsocketContext);
|
||||
if (context === null) {
|
||||
throw new Error("useWebsocket must be used within WebsocketContext");
|
||||
}
|
||||
return context;
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
import React, { useState } from "react";
|
||||
import useWebSocket from "react-use-websocket";
|
||||
|
||||
import { SplashLoader } from "../../components/splash-loader";
|
||||
import { SplashScreen } from "../../components/splash-screen";
|
||||
import { DATA_SOURCES } from "../../config";
|
||||
import { TendermintWebsocketContext } from "./tendermint-websocket-context";
|
||||
|
||||
/**
|
||||
* Provides a single, shared, websocket instance to the entire app to prevent recreation on every render
|
||||
*/
|
||||
export const TendermintWebsocketProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: JSX.Element;
|
||||
}) => {
|
||||
const [socketUrl] = useState(DATA_SOURCES.tendermintWebsocketUrl);
|
||||
const contextShape = useWebSocket(socketUrl);
|
||||
|
||||
if (!contextShape) {
|
||||
return (
|
||||
<SplashScreen>
|
||||
<SplashLoader />
|
||||
</SplashScreen>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TendermintWebsocketContext.Provider value={{ ...contextShape }}>
|
||||
{children}
|
||||
</TendermintWebsocketContext.Provider>
|
||||
);
|
||||
};
|
86
apps/block-explorer/src/hooks/use-fetch.tsx
Normal file
86
apps/block-explorer/src/hooks/use-fetch.tsx
Normal file
@ -0,0 +1,86 @@
|
||||
import { useEffect, useReducer, useRef } from "react";
|
||||
|
||||
interface State<T> {
|
||||
data?: T;
|
||||
error?: Error;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
enum ActionType {
|
||||
LOADING = "LOADING",
|
||||
ERROR = "ERROR",
|
||||
FETCHED = "FETCHED",
|
||||
}
|
||||
|
||||
// discriminated union type
|
||||
type Action<T> =
|
||||
| { type: ActionType.LOADING }
|
||||
| { type: ActionType.FETCHED; payload: T }
|
||||
| { type: ActionType.ERROR; error: Error };
|
||||
|
||||
function useFetch<T = unknown>(url?: string, options?: RequestInit): State<T> {
|
||||
// Used to prevent state update if the component is unmounted
|
||||
const cancelRequest = useRef<boolean>(false);
|
||||
|
||||
const initialState: State<T> = {
|
||||
error: undefined,
|
||||
data: undefined,
|
||||
loading: false,
|
||||
};
|
||||
|
||||
// Keep state logic separated
|
||||
const fetchReducer = (state: State<T>, action: Action<T>): State<T> => {
|
||||
switch (action.type) {
|
||||
case ActionType.LOADING:
|
||||
return { ...initialState, loading: true };
|
||||
case ActionType.FETCHED:
|
||||
return { ...initialState, data: action.payload, loading: false };
|
||||
case ActionType.ERROR:
|
||||
return { ...initialState, error: action.error, loading: false };
|
||||
}
|
||||
};
|
||||
|
||||
const [state, dispatch] = useReducer(fetchReducer, initialState);
|
||||
|
||||
useEffect(() => {
|
||||
// Do nothing if the url is not given
|
||||
if (!url) return;
|
||||
|
||||
const fetchData = async () => {
|
||||
dispatch({ type: ActionType.LOADING });
|
||||
|
||||
try {
|
||||
const response = await fetch(url, options);
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as T;
|
||||
if ("error" in data) {
|
||||
// @ts-ignore
|
||||
throw new Error(data.error);
|
||||
}
|
||||
if (cancelRequest.current) return;
|
||||
|
||||
dispatch({ type: ActionType.FETCHED, payload: data });
|
||||
} catch (error) {
|
||||
if (cancelRequest.current) return;
|
||||
|
||||
dispatch({ type: ActionType.ERROR, error: error as Error });
|
||||
}
|
||||
};
|
||||
|
||||
void fetchData();
|
||||
|
||||
// Use the cleanup function for avoiding a possibly...
|
||||
// ...state update after the component was unmounted
|
||||
return () => {
|
||||
cancelRequest.current = true;
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [url]);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
export default useFetch;
|
68
apps/block-explorer/src/hooks/use-tendermint-websocket.tsx
Normal file
68
apps/block-explorer/src/hooks/use-tendermint-websocket.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import React from "react";
|
||||
import { useTendermintWebsocketContext } from "../contexts/websocket/tendermint-websocket-context";
|
||||
|
||||
export interface TendermintWebsocketQuery {
|
||||
query: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the ID generation, subscription and unsubscription logic for tendermint websocket queries
|
||||
*
|
||||
* Subscribes when called and cleans up the subscription on destroy.
|
||||
*
|
||||
* Creates IDs for messages uniquely so only the current subscription is updated
|
||||
*
|
||||
* If a bufferSize is passed in then a circular buffer is created, with the oldest messages being discarded to prevent memory leeks
|
||||
*
|
||||
* @param message The query to be sent to tendermint see: https://docs.tendermint.com/master/rpc/#/Websocket/subscribe for syntax for query parameter
|
||||
* @param bufferSize
|
||||
* @returns
|
||||
*/
|
||||
export const useTendermintWebsocket = function <T>(
|
||||
message: TendermintWebsocketQuery,
|
||||
bufferSize?: number
|
||||
) {
|
||||
const { sendMessage, lastMessage } = useTendermintWebsocketContext();
|
||||
// @ts-ignore
|
||||
const [id] = React.useState(crypto.randomUUID());
|
||||
const [messages, setMessages] = React.useState<MessageEvent<T>[]>([]);
|
||||
|
||||
const [subMsg] = React.useState({
|
||||
jsonrpc: "2.0",
|
||||
method: "subscribe",
|
||||
id,
|
||||
params: {
|
||||
...message,
|
||||
},
|
||||
});
|
||||
const [unsubMsg] = React.useState({
|
||||
...subMsg,
|
||||
method: "unsubscribe",
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (lastMessage && lastMessage.data) {
|
||||
const data = JSON.parse(lastMessage.data);
|
||||
if (data.id === id) {
|
||||
setMessages((prev) => {
|
||||
if (bufferSize && prev.length >= bufferSize) {
|
||||
return [data, ...prev.slice(0, bufferSize - 1)];
|
||||
} else {
|
||||
return [data, ...prev];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [bufferSize, id, lastMessage, setMessages]);
|
||||
|
||||
React.useEffect(() => {
|
||||
sendMessage(JSON.stringify(subMsg));
|
||||
return () => {
|
||||
sendMessage(JSON.stringify(unsubMsg));
|
||||
};
|
||||
}, [subMsg, sendMessage, unsubMsg]);
|
||||
|
||||
return {
|
||||
messages,
|
||||
};
|
||||
};
|
16
apps/block-explorer/src/index.tsx
Normal file
16
apps/block-explorer/src/index.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import App from "./App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
53
apps/block-explorer/src/lib/apollo-client.tsx
Normal file
53
apps/block-explorer/src/lib/apollo-client.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { ApolloClient, from, HttpLink, InMemoryCache } from "@apollo/client";
|
||||
import { onError } from "@apollo/client/link/error";
|
||||
import { RetryLink } from "@apollo/client/link/retry";
|
||||
|
||||
export function createClient(base?: string) {
|
||||
if (!base) {
|
||||
throw new Error("Base must be passed into createClient!");
|
||||
}
|
||||
const gqlPath = "query";
|
||||
const urlHTTP = new URL(gqlPath, base);
|
||||
const urlWS = new URL(gqlPath, base);
|
||||
// Replace http with ws, preserving if its a secure connection eg. https => wss
|
||||
urlWS.protocol = urlWS.protocol.replace("http", "ws");
|
||||
|
||||
const cache = new InMemoryCache({
|
||||
typePolicies: {
|
||||
Query: {},
|
||||
Account: {
|
||||
keyFields: false,
|
||||
fields: {
|
||||
balanceFormatted: {},
|
||||
},
|
||||
},
|
||||
Node: {
|
||||
keyFields: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const retryLink = new RetryLink({
|
||||
delay: {
|
||||
initial: 300,
|
||||
max: 10000,
|
||||
jitter: true,
|
||||
},
|
||||
});
|
||||
|
||||
const httpLink = new HttpLink({
|
||||
uri: urlHTTP.href,
|
||||
credentials: "same-origin",
|
||||
});
|
||||
|
||||
const errorLink = onError(({ graphQLErrors, networkError }) => {
|
||||
console.log(graphQLErrors);
|
||||
console.log(networkError);
|
||||
});
|
||||
|
||||
return new ApolloClient({
|
||||
connectToDevTools: process.env.NODE_ENV === "development",
|
||||
link: from([errorLink, retryLink, httpLink]),
|
||||
cache,
|
||||
});
|
||||
}
|
1
apps/block-explorer/src/react-app-env.d.ts
vendored
Normal file
1
apps/block-explorer/src/react-app-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
15
apps/block-explorer/src/reportWebVitals.ts
Normal file
15
apps/block-explorer/src/reportWebVitals.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { ReportHandler } from 'web-vitals';
|
||||
|
||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
95
apps/block-explorer/src/routes/assets/__generated__/AssetsQuery.ts
generated
Normal file
95
apps/block-explorer/src/routes/assets/__generated__/AssetsQuery.ts
generated
Normal file
@ -0,0 +1,95 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AccountType } from "./../../../__generated__/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: AssetsQuery
|
||||
// ====================================================
|
||||
|
||||
export interface AssetsQuery_assets_source_ERC20 {
|
||||
__typename: "ERC20";
|
||||
/**
|
||||
* The address of the erc20 contract
|
||||
*/
|
||||
contractAddress: string;
|
||||
}
|
||||
|
||||
export interface AssetsQuery_assets_source_BuiltinAsset {
|
||||
__typename: "BuiltinAsset";
|
||||
/**
|
||||
* Maximum amount that can be requested by a party through the built-in asset faucet at a time
|
||||
*/
|
||||
maxFaucetAmountMint: string;
|
||||
}
|
||||
|
||||
export type AssetsQuery_assets_source = AssetsQuery_assets_source_ERC20 | AssetsQuery_assets_source_BuiltinAsset;
|
||||
|
||||
export interface AssetsQuery_assets_infrastructureFeeAccount_market {
|
||||
__typename: "Market";
|
||||
/**
|
||||
* Market ID
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface AssetsQuery_assets_infrastructureFeeAccount {
|
||||
__typename: "Account";
|
||||
/**
|
||||
* Account type (General, Margin, etc)
|
||||
*/
|
||||
type: AccountType;
|
||||
/**
|
||||
* Balance as string - current account balance (approx. as balances can be updated several times per second)
|
||||
*/
|
||||
balance: string;
|
||||
/**
|
||||
* Market (only relevant to margin accounts)
|
||||
*/
|
||||
market: AssetsQuery_assets_infrastructureFeeAccount_market | null;
|
||||
}
|
||||
|
||||
export interface AssetsQuery_assets {
|
||||
__typename: "Asset";
|
||||
/**
|
||||
* The id of the asset
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The full name of the asset (e.g: Great British Pound)
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* The symbol of the asset (e.g: GBP)
|
||||
*/
|
||||
symbol: string;
|
||||
/**
|
||||
* The total supply of the market
|
||||
*/
|
||||
totalSupply: string;
|
||||
/**
|
||||
* The precision of the asset
|
||||
*/
|
||||
decimals: number;
|
||||
/**
|
||||
* The min stake to become an lp for any market using this asset for settlement
|
||||
*/
|
||||
minLpStake: string;
|
||||
/**
|
||||
* The origin source of the asset (e.g: an erc20 asset)
|
||||
*/
|
||||
source: AssetsQuery_assets_source;
|
||||
/**
|
||||
* The infrastructure fee account for this asset
|
||||
*/
|
||||
infrastructureFeeAccount: AssetsQuery_assets_infrastructureFeeAccount;
|
||||
}
|
||||
|
||||
export interface AssetsQuery {
|
||||
/**
|
||||
* The list of all assets in use in the vega network
|
||||
*/
|
||||
assets: AssetsQuery_assets[] | null;
|
||||
}
|
42
apps/block-explorer/src/routes/assets/index.tsx
Normal file
42
apps/block-explorer/src/routes/assets/index.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import { gql, useQuery } from "@apollo/client";
|
||||
import { AssetsQuery } from "./__generated__/AssetsQuery";
|
||||
|
||||
export const ASSETS_QUERY = gql`
|
||||
query AssetsQuery {
|
||||
assets {
|
||||
id
|
||||
name
|
||||
symbol
|
||||
totalSupply
|
||||
decimals
|
||||
minLpStake
|
||||
source {
|
||||
... on ERC20 {
|
||||
contractAddress
|
||||
}
|
||||
... on BuiltinAsset {
|
||||
maxFaucetAmountMint
|
||||
}
|
||||
}
|
||||
infrastructureFeeAccount {
|
||||
type
|
||||
balance
|
||||
market {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Assets = () => {
|
||||
const { data } = useQuery<AssetsQuery>(ASSETS_QUERY);
|
||||
return (
|
||||
<section>
|
||||
<h1>Assets</h1>
|
||||
<pre>{JSON.stringify(data, null, " ")}</pre>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Assets;
|
41
apps/block-explorer/src/routes/blocks/home/index.tsx
Normal file
41
apps/block-explorer/src/routes/blocks/home/index.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import { DATA_SOURCES } from "../../../config";
|
||||
import useFetch from "../../../hooks/use-fetch";
|
||||
import { NewBlockMessage } from "../tendermint-new-block";
|
||||
import { TendermintBlockchainResponse } from "../tendermint-blockchain-response";
|
||||
import { useTendermintWebsocket } from "../../../hooks/use-tendermint-websocket";
|
||||
|
||||
const MAX_BLOCKS = 10;
|
||||
|
||||
const Blocks = () => {
|
||||
const { messages: blocks } = useTendermintWebsocket<NewBlockMessage>(
|
||||
{
|
||||
query: "tm.event = 'NewBlock'",
|
||||
},
|
||||
MAX_BLOCKS
|
||||
);
|
||||
const { data } = useFetch<TendermintBlockchainResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/blockchain`
|
||||
);
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h1>Blocks</h1>
|
||||
<h2>Blocks from blockchain</h2>
|
||||
{`${DATA_SOURCES.tendermintUrl}/blockchain`}
|
||||
<br />
|
||||
<div>Height: {data?.result?.last_height || 0}</div>
|
||||
<br />
|
||||
<div>
|
||||
<br />
|
||||
<pre>{JSON.stringify(data, null, " ")}</pre>
|
||||
</div>
|
||||
<h2>Blocks streamed in</h2>
|
||||
<div>
|
||||
<br />
|
||||
<pre>{JSON.stringify(blocks, null, " ")}</pre>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export { Blocks };
|
40
apps/block-explorer/src/routes/blocks/id/index.tsx
Normal file
40
apps/block-explorer/src/routes/blocks/id/index.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import React from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { DATA_SOURCES } from "../../../config";
|
||||
import useFetch from "../../../hooks/use-fetch";
|
||||
import { ChainExplorerTxResponse } from "../../types/chain-explorer-response";
|
||||
import { TendermintBlocksResponse } from "../tendermint-blocks-response";
|
||||
|
||||
const Block = () => {
|
||||
const { block } = useParams<{ block: string }>();
|
||||
const { data: decodedBlockData } = useFetch<ChainExplorerTxResponse[]>(
|
||||
DATA_SOURCES.chainExplorerUrl,
|
||||
{
|
||||
method: "POST",
|
||||
mode: "cors",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
block_height: parseInt(block),
|
||||
node_url: `${DATA_SOURCES.tendermintUrl}/`,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const { data: blockData } = useFetch<TendermintBlocksResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/block?height=${block}`
|
||||
);
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h1>block</h1>
|
||||
<h2>Tendermint Data</h2>
|
||||
<pre>{JSON.stringify(blockData, null, " ")}</pre>
|
||||
<h2>Decoded data</h2>
|
||||
<pre>{JSON.stringify(decodedBlockData, null, " ")}</pre>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export { Block };
|
21
apps/block-explorer/src/routes/blocks/index.tsx
Normal file
21
apps/block-explorer/src/routes/blocks/index.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import { Route, Switch, useRouteMatch } from "react-router-dom";
|
||||
import { Blocks } from "./home";
|
||||
import { Block } from "./id";
|
||||
|
||||
const BlockPage = () => {
|
||||
const match = useRouteMatch();
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Route path={match.path} exact={true}>
|
||||
<Blocks />
|
||||
</Route>
|
||||
<Route path={`${match.path}/:block`}>
|
||||
<Block />
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlockPage;
|
53
apps/block-explorer/src/routes/blocks/tendermint-blockchain-response.d.ts
vendored
Normal file
53
apps/block-explorer/src/routes/blocks/tendermint-blockchain-response.d.ts
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
export interface Parts {
|
||||
total: number;
|
||||
hash: string;
|
||||
}
|
||||
|
||||
export interface BlockId {
|
||||
hash: string;
|
||||
parts: Parts;
|
||||
}
|
||||
|
||||
export interface Version {
|
||||
block: string;
|
||||
}
|
||||
|
||||
export interface LastBlockId {
|
||||
hash: string;
|
||||
parts: Parts;
|
||||
}
|
||||
|
||||
export interface Header {
|
||||
version: Version;
|
||||
chain_id: string;
|
||||
height: string;
|
||||
time: string;
|
||||
last_block_id: LastBlockId;
|
||||
last_commit_hash: string;
|
||||
data_hash: string;
|
||||
validators_hash: string;
|
||||
next_validators_hash: string;
|
||||
consensus_hash: string;
|
||||
app_hash: string;
|
||||
last_results_hash: string;
|
||||
evidence_hash: string;
|
||||
proposer_address: string;
|
||||
}
|
||||
|
||||
export interface BlockMeta {
|
||||
block_id: BlockId;
|
||||
block_size: string;
|
||||
header: Header;
|
||||
num_txs: string;
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
last_height: string;
|
||||
block_metas: BlockMeta[];
|
||||
}
|
||||
|
||||
export interface TendermintBlockchainResponse {
|
||||
jsonrpc: string;
|
||||
id: number;
|
||||
result: Result;
|
||||
}
|
70
apps/block-explorer/src/routes/blocks/tendermint-blocks-response.d.ts
vendored
Normal file
70
apps/block-explorer/src/routes/blocks/tendermint-blocks-response.d.ts
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
export interface Parts {
|
||||
total: number;
|
||||
hash: string;
|
||||
}
|
||||
|
||||
export interface BlockId {
|
||||
hash: string;
|
||||
parts: Parts;
|
||||
}
|
||||
|
||||
export interface Version {
|
||||
block: string;
|
||||
}
|
||||
|
||||
export interface Header {
|
||||
version: Version;
|
||||
chain_id: string;
|
||||
height: string;
|
||||
time: string;
|
||||
last_block_id: BlockId;
|
||||
last_commit_hash: string;
|
||||
data_hash: string;
|
||||
validators_hash: string;
|
||||
next_validators_hash: string;
|
||||
consensus_hash: string;
|
||||
app_hash: string;
|
||||
last_results_hash: string;
|
||||
evidence_hash: string;
|
||||
proposer_address: string;
|
||||
}
|
||||
|
||||
export interface Data {
|
||||
txs: string[];
|
||||
}
|
||||
|
||||
export interface Evidence {
|
||||
evidence: any[];
|
||||
}
|
||||
|
||||
export interface Signature {
|
||||
block_id_flag: number;
|
||||
validator_address: string;
|
||||
timestamp: string;
|
||||
signature: string;
|
||||
}
|
||||
|
||||
export interface LastCommit {
|
||||
height: string;
|
||||
round: number;
|
||||
block_id: BlockId;
|
||||
signatures: Signature[];
|
||||
}
|
||||
|
||||
export interface Block {
|
||||
header: Header;
|
||||
data: Data;
|
||||
evidence: Evidence;
|
||||
last_commit: LastCommit;
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
block_id: BlockId;
|
||||
block: Block;
|
||||
}
|
||||
|
||||
export interface TendermintBlocksResponse {
|
||||
jsonrpc: string;
|
||||
id: number;
|
||||
result: Result;
|
||||
}
|
97
apps/block-explorer/src/routes/blocks/tendermint-new-block.d.ts
vendored
Normal file
97
apps/block-explorer/src/routes/blocks/tendermint-new-block.d.ts
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
export interface Version {
|
||||
block: string;
|
||||
}
|
||||
|
||||
export interface Parts {
|
||||
total: number;
|
||||
hash: string;
|
||||
}
|
||||
|
||||
export interface LastBlockId {
|
||||
hash: string;
|
||||
parts: Parts;
|
||||
}
|
||||
|
||||
export interface Header {
|
||||
version: Version;
|
||||
chain_id: string;
|
||||
height: string;
|
||||
time: string;
|
||||
last_block_id: LastBlockId;
|
||||
last_commit_hash: string;
|
||||
data_hash: string;
|
||||
validators_hash: string;
|
||||
next_validators_hash: string;
|
||||
consensus_hash: string;
|
||||
app_hash: string;
|
||||
last_results_hash: string;
|
||||
evidence_hash: string;
|
||||
proposer_address: string;
|
||||
}
|
||||
|
||||
export interface TransactionData {
|
||||
txs: string[];
|
||||
}
|
||||
|
||||
export interface Evidence {
|
||||
evidence: any[];
|
||||
}
|
||||
|
||||
export interface BlockId {
|
||||
hash: string;
|
||||
parts: Parts;
|
||||
}
|
||||
|
||||
export interface Signature {
|
||||
block_id_flag: number;
|
||||
validator_address: string;
|
||||
timestamp: string;
|
||||
signature: string;
|
||||
}
|
||||
|
||||
export interface LastCommit {
|
||||
height: string;
|
||||
round: number;
|
||||
block_id: BlockId;
|
||||
signatures: Signature[];
|
||||
}
|
||||
|
||||
export interface Block {
|
||||
header: Header;
|
||||
data: TransactionData;
|
||||
evidence: Evidence;
|
||||
last_commit: LastCommit;
|
||||
}
|
||||
|
||||
export interface ResultBeginBlock {}
|
||||
|
||||
export interface ResultEndBlock {
|
||||
validator_updates?: any;
|
||||
}
|
||||
|
||||
export interface Value {
|
||||
block: Block;
|
||||
result_begin_block: ResultBeginBlock;
|
||||
result_end_block: ResultEndBlock;
|
||||
}
|
||||
|
||||
export interface Data {
|
||||
type: string;
|
||||
value: Value;
|
||||
}
|
||||
|
||||
export interface Events {
|
||||
"tm.event": string[];
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
query: string;
|
||||
data: Data;
|
||||
events: Events;
|
||||
}
|
||||
|
||||
export interface NewBlockMessage {
|
||||
jsonrpc: string;
|
||||
id: string;
|
||||
result: Result;
|
||||
}
|
17
apps/block-explorer/src/routes/genesis/index.tsx
Normal file
17
apps/block-explorer/src/routes/genesis/index.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { DATA_SOURCES } from "../../config";
|
||||
import useFetch from "../../hooks/use-fetch";
|
||||
import { TendermintGenesisResponse } from "./tendermint-genesis-response";
|
||||
|
||||
const Genesis = () => {
|
||||
const { data: genesis } = useFetch<TendermintGenesisResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/genesis`
|
||||
);
|
||||
return (
|
||||
<section>
|
||||
<h1>Genesis</h1>
|
||||
<pre>{JSON.stringify(genesis, null, " ")}</pre>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Genesis;
|
112
apps/block-explorer/src/routes/genesis/tendermint-genesis-response.d.ts
vendored
Normal file
112
apps/block-explorer/src/routes/genesis/tendermint-genesis-response.d.ts
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
export interface Block {
|
||||
max_bytes: string;
|
||||
max_gas: string;
|
||||
time_iota_ms: string;
|
||||
}
|
||||
|
||||
export interface Evidence {
|
||||
max_age_num_blocks: string;
|
||||
max_age_duration: string;
|
||||
}
|
||||
|
||||
export interface ValidatorAddresses {
|
||||
pub_key_types: string[];
|
||||
}
|
||||
|
||||
export interface Version {}
|
||||
|
||||
export interface ConsensusParams {
|
||||
block: Block;
|
||||
evidence: Evidence;
|
||||
validator: ValidatorAddresses;
|
||||
version: Version;
|
||||
}
|
||||
|
||||
export interface PubKey {
|
||||
type: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface Validator {
|
||||
address: string;
|
||||
pub_key: PubKey;
|
||||
power: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Erc20 {
|
||||
contract_address: string;
|
||||
}
|
||||
|
||||
export interface Erc20Source {
|
||||
erc20: Erc20;
|
||||
}
|
||||
|
||||
export interface Asset {
|
||||
decimals: number;
|
||||
min_lp_stake: string;
|
||||
name: string;
|
||||
source: Erc20Source | BuiltinAssetSource;
|
||||
symbol: string;
|
||||
total_supply: string;
|
||||
}
|
||||
|
||||
export interface BuiltinAsset {
|
||||
max_faucet_amount_mint: string;
|
||||
}
|
||||
|
||||
export interface BuiltinAssetSource {
|
||||
builtin_asset: BuiltinAsset;
|
||||
}
|
||||
|
||||
export interface Assets {
|
||||
[key: string]: Asset;
|
||||
}
|
||||
|
||||
export interface Network {
|
||||
replay_attack_threshold: number;
|
||||
}
|
||||
|
||||
export interface NetworkLimits {
|
||||
bootstrap_block_count: number;
|
||||
propose_asset_enabled: boolean;
|
||||
propose_asset_enabled_from: Date;
|
||||
propose_market_enabled: boolean;
|
||||
propose_market_enabled_from: Date;
|
||||
}
|
||||
|
||||
export interface NetworkParameters {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface Validators {
|
||||
[key: string]: Validator;
|
||||
}
|
||||
|
||||
export interface AppState {
|
||||
assets: Assets;
|
||||
network: Network;
|
||||
network_limits: NetworkLimits;
|
||||
network_parameters: NetworkParameters;
|
||||
validators: Validators;
|
||||
}
|
||||
|
||||
export interface Genesis {
|
||||
genesis_time: Date;
|
||||
chain_id: string;
|
||||
initial_height: string;
|
||||
consensus_params: ConsensusParams;
|
||||
validators: Validator[];
|
||||
app_hash: string;
|
||||
app_state: AppState;
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
genesis: Genesis;
|
||||
}
|
||||
|
||||
export interface TendermintGenesisResponse {
|
||||
jsonrpc: string;
|
||||
id: number;
|
||||
result: Result;
|
||||
}
|
265
apps/block-explorer/src/routes/governance/__generated__/ProposalsQuery.ts
generated
Normal file
265
apps/block-explorer/src/routes/governance/__generated__/ProposalsQuery.ts
generated
Normal file
@ -0,0 +1,265 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { ProposalState, ProposalRejectionReason, VoteValue } from "./../../../__generated__/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: ProposalsQuery
|
||||
// ====================================================
|
||||
|
||||
export interface ProposalsQuery_proposals_party {
|
||||
__typename: "Party";
|
||||
/**
|
||||
* Party identifier
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_NewMarket_instrument {
|
||||
__typename: "InstrumentConfiguration";
|
||||
/**
|
||||
* Full and fairly descriptive name for the instrument
|
||||
*/
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_NewMarket {
|
||||
__typename: "NewMarket";
|
||||
/**
|
||||
* New market instrument configuration
|
||||
*/
|
||||
instrument: ProposalsQuery_proposals_terms_change_NewMarket_instrument;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_UpdateMarket {
|
||||
__typename: "UpdateMarket";
|
||||
marketId: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_NewAsset_source_BuiltinAsset {
|
||||
__typename: "BuiltinAsset";
|
||||
/**
|
||||
* Maximum amount that can be requested by a party through the built-in asset faucet at a time
|
||||
*/
|
||||
maxFaucetAmountMint: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_NewAsset_source_ERC20 {
|
||||
__typename: "ERC20";
|
||||
/**
|
||||
* The address of the erc20 contract
|
||||
*/
|
||||
contractAddress: string;
|
||||
}
|
||||
|
||||
export type ProposalsQuery_proposals_terms_change_NewAsset_source = ProposalsQuery_proposals_terms_change_NewAsset_source_BuiltinAsset | ProposalsQuery_proposals_terms_change_NewAsset_source_ERC20;
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_NewAsset {
|
||||
__typename: "NewAsset";
|
||||
/**
|
||||
* The symbol of the asset (e.g: GBP)
|
||||
*/
|
||||
symbol: string;
|
||||
/**
|
||||
* the source of the new Asset
|
||||
*/
|
||||
source: ProposalsQuery_proposals_terms_change_NewAsset_source;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_UpdateNetworkParameter_networkParameter {
|
||||
__typename: "NetworkParameter";
|
||||
/**
|
||||
* The name of the network parameter
|
||||
*/
|
||||
key: string;
|
||||
/**
|
||||
* The value of the network parameter
|
||||
*/
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_terms_change_UpdateNetworkParameter {
|
||||
__typename: "UpdateNetworkParameter";
|
||||
networkParameter: ProposalsQuery_proposals_terms_change_UpdateNetworkParameter_networkParameter;
|
||||
}
|
||||
|
||||
export type ProposalsQuery_proposals_terms_change = ProposalsQuery_proposals_terms_change_NewMarket | ProposalsQuery_proposals_terms_change_UpdateMarket | ProposalsQuery_proposals_terms_change_NewAsset | ProposalsQuery_proposals_terms_change_UpdateNetworkParameter;
|
||||
|
||||
export interface ProposalsQuery_proposals_terms {
|
||||
__typename: "ProposalTerms";
|
||||
/**
|
||||
* RFC3339Nano time and date when voting closes for this proposal.
|
||||
* Constrained by "minClose" and "maxClose" network parameters.
|
||||
*/
|
||||
closingDatetime: string;
|
||||
/**
|
||||
* RFC3339Nano time and date when this proposal is executed (if passed). Note that it has to be after closing date time.
|
||||
* Constrained by "minEnactInSeconds" and "maxEnactInSeconds" network parameters.
|
||||
*/
|
||||
enactmentDatetime: string;
|
||||
/**
|
||||
* Actual change being introduced by the proposal - action the proposal triggers if passed and enacted.
|
||||
*/
|
||||
change: ProposalsQuery_proposals_terms_change;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_yes_votes_party_stake {
|
||||
__typename: "PartyStake";
|
||||
/**
|
||||
* The stake currently available for the party
|
||||
*/
|
||||
currentStakeAvailable: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_yes_votes_party {
|
||||
__typename: "Party";
|
||||
/**
|
||||
* Party identifier
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The staking informations for this Party
|
||||
*/
|
||||
stake: ProposalsQuery_proposals_votes_yes_votes_party_stake;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_yes_votes {
|
||||
__typename: "Vote";
|
||||
/**
|
||||
* The vote value cast
|
||||
*/
|
||||
value: VoteValue;
|
||||
/**
|
||||
* The party casting the vote
|
||||
*/
|
||||
party: ProposalsQuery_proposals_votes_yes_votes_party;
|
||||
/**
|
||||
* RFC3339Nano time and date when the vote reached Vega network
|
||||
*/
|
||||
datetime: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_yes {
|
||||
__typename: "ProposalVoteSide";
|
||||
/**
|
||||
* Total tokens of governance token from the votes casted for this side
|
||||
*/
|
||||
totalTokens: string;
|
||||
/**
|
||||
* Total number of votes casted for this side
|
||||
*/
|
||||
totalNumber: string;
|
||||
/**
|
||||
* All votes casted for this side
|
||||
*/
|
||||
votes: ProposalsQuery_proposals_votes_yes_votes[] | null;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_no_votes_party_stake {
|
||||
__typename: "PartyStake";
|
||||
/**
|
||||
* The stake currently available for the party
|
||||
*/
|
||||
currentStakeAvailable: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_no_votes_party {
|
||||
__typename: "Party";
|
||||
/**
|
||||
* Party identifier
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The staking informations for this Party
|
||||
*/
|
||||
stake: ProposalsQuery_proposals_votes_no_votes_party_stake;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_no_votes {
|
||||
__typename: "Vote";
|
||||
/**
|
||||
* The vote value cast
|
||||
*/
|
||||
value: VoteValue;
|
||||
/**
|
||||
* The party casting the vote
|
||||
*/
|
||||
party: ProposalsQuery_proposals_votes_no_votes_party;
|
||||
/**
|
||||
* RFC3339Nano time and date when the vote reached Vega network
|
||||
*/
|
||||
datetime: string;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes_no {
|
||||
__typename: "ProposalVoteSide";
|
||||
/**
|
||||
* Total tokens of governance token from the votes casted for this side
|
||||
*/
|
||||
totalTokens: string;
|
||||
/**
|
||||
* Total number of votes casted for this side
|
||||
*/
|
||||
totalNumber: string;
|
||||
/**
|
||||
* All votes casted for this side
|
||||
*/
|
||||
votes: ProposalsQuery_proposals_votes_no_votes[] | null;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals_votes {
|
||||
__typename: "ProposalVotes";
|
||||
/**
|
||||
* Yes votes cast for this proposal
|
||||
*/
|
||||
yes: ProposalsQuery_proposals_votes_yes;
|
||||
/**
|
||||
* No votes cast for this proposal
|
||||
*/
|
||||
no: ProposalsQuery_proposals_votes_no;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery_proposals {
|
||||
__typename: "Proposal";
|
||||
/**
|
||||
* Proposal ID that is filled by VEGA once proposal reaches the network
|
||||
*/
|
||||
id: string | null;
|
||||
/**
|
||||
* A UUID reference to aid tracking proposals on VEGA
|
||||
*/
|
||||
reference: string;
|
||||
/**
|
||||
* State of the proposal
|
||||
*/
|
||||
state: ProposalState;
|
||||
/**
|
||||
* RFC3339Nano time and date when the proposal reached Vega network
|
||||
*/
|
||||
datetime: string;
|
||||
/**
|
||||
* Reason for the proposal to be rejected by the core
|
||||
*/
|
||||
rejectionReason: ProposalRejectionReason | null;
|
||||
/**
|
||||
* Party that prepared the proposal
|
||||
*/
|
||||
party: ProposalsQuery_proposals_party;
|
||||
/**
|
||||
* Terms of the proposal
|
||||
*/
|
||||
terms: ProposalsQuery_proposals_terms;
|
||||
/**
|
||||
* Votes cast for this proposal
|
||||
*/
|
||||
votes: ProposalsQuery_proposals_votes;
|
||||
}
|
||||
|
||||
export interface ProposalsQuery {
|
||||
/**
|
||||
* All governance proposals in the VEGA network
|
||||
*/
|
||||
proposals: ProposalsQuery_proposals[] | null;
|
||||
}
|
91
apps/block-explorer/src/routes/governance/index.tsx
Normal file
91
apps/block-explorer/src/routes/governance/index.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
import { gql, useQuery } from "@apollo/client";
|
||||
import { ProposalsQuery } from "./__generated__/ProposalsQuery";
|
||||
|
||||
const PROPOSAL_QUERY = gql`
|
||||
query ProposalsQuery {
|
||||
proposals {
|
||||
id
|
||||
reference
|
||||
state
|
||||
datetime
|
||||
rejectionReason
|
||||
party {
|
||||
id
|
||||
}
|
||||
terms {
|
||||
closingDatetime
|
||||
enactmentDatetime
|
||||
change {
|
||||
... on NewMarket {
|
||||
instrument {
|
||||
name
|
||||
}
|
||||
}
|
||||
... on UpdateMarket {
|
||||
marketId
|
||||
}
|
||||
... on NewAsset {
|
||||
__typename
|
||||
symbol
|
||||
source {
|
||||
... on BuiltinAsset {
|
||||
maxFaucetAmountMint
|
||||
}
|
||||
... on ERC20 {
|
||||
contractAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
... on UpdateNetworkParameter {
|
||||
networkParameter {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
votes {
|
||||
yes {
|
||||
totalTokens
|
||||
totalNumber
|
||||
votes {
|
||||
value
|
||||
party {
|
||||
id
|
||||
stake {
|
||||
currentStakeAvailable
|
||||
}
|
||||
}
|
||||
datetime
|
||||
}
|
||||
}
|
||||
no {
|
||||
totalTokens
|
||||
totalNumber
|
||||
votes {
|
||||
value
|
||||
party {
|
||||
id
|
||||
stake {
|
||||
currentStakeAvailable
|
||||
}
|
||||
}
|
||||
datetime
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Governance = () => {
|
||||
const { data } = useQuery<ProposalsQuery>(PROPOSAL_QUERY);
|
||||
return (
|
||||
<section>
|
||||
<h1>Governance</h1>
|
||||
<pre>{JSON.stringify(data, null, " ")}</pre>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Governance;
|
9
apps/block-explorer/src/routes/home/index.tsx
Normal file
9
apps/block-explorer/src/routes/home/index.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
const Home = () => {
|
||||
return (
|
||||
<section>
|
||||
<h1>Home page content</h1>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
35
apps/block-explorer/src/routes/index.tsx
Normal file
35
apps/block-explorer/src/routes/index.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import React from "react";
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import { RouteErrorBoundary } from "../components/router-error-boundary";
|
||||
|
||||
import { SplashLoader } from "../components/splash-loader";
|
||||
import { SplashScreen } from "../components/splash-screen";
|
||||
import routerConfig from "./router-config";
|
||||
|
||||
export interface RouteChildProps {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export const AppRouter = () => {
|
||||
const splashLoading = (
|
||||
<SplashScreen>
|
||||
<SplashLoader />
|
||||
</SplashScreen>
|
||||
);
|
||||
|
||||
return (
|
||||
<RouteErrorBoundary>
|
||||
<React.Suspense fallback={splashLoading}>
|
||||
<Switch>
|
||||
{routerConfig.map(
|
||||
({ path, component: Component, exact = false, name }) => (
|
||||
<Route key={name} path={path} exact={exact}>
|
||||
<Component />
|
||||
</Route>
|
||||
)
|
||||
)}
|
||||
</Switch>
|
||||
</React.Suspense>
|
||||
</RouteErrorBoundary>
|
||||
);
|
||||
};
|
549
apps/block-explorer/src/routes/markets/__generated__/MarketsQuery.ts
generated
Normal file
549
apps/block-explorer/src/routes/markets/__generated__/MarketsQuery.ts
generated
Normal file
@ -0,0 +1,549 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { MarketTradingMode, MarketState, AccountType, AuctionTrigger } from "./../../../__generated__/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: MarketsQuery
|
||||
// ====================================================
|
||||
|
||||
export interface MarketsQuery_markets_fees_factors {
|
||||
__typename: "FeeFactors";
|
||||
/**
|
||||
* The factor applied to calculate MakerFees, a non-negative float
|
||||
*/
|
||||
makerFee: string;
|
||||
/**
|
||||
* The factor applied to calculate InfrastructureFees, a non-negative float
|
||||
*/
|
||||
infrastructureFee: string;
|
||||
/**
|
||||
* The factor applied to calculate LiquidityFees, a non-negative float
|
||||
*/
|
||||
liquidityFee: string;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_fees {
|
||||
__typename: "Fees";
|
||||
/**
|
||||
* The factors used to calculate the different fees
|
||||
*/
|
||||
factors: MarketsQuery_markets_fees_factors;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_tradableInstrument_instrument_metadata {
|
||||
__typename: "InstrumentMetadata";
|
||||
/**
|
||||
* An arbitrary list of tags to associated to associate to the Instrument (string list)
|
||||
*/
|
||||
tags: string[] | null;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_tradableInstrument_instrument_product_settlementAsset_globalRewardPoolAccount {
|
||||
__typename: "Account";
|
||||
/**
|
||||
* Balance as string - current account balance (approx. as balances can be updated several times per second)
|
||||
*/
|
||||
balance: string;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_tradableInstrument_instrument_product_settlementAsset {
|
||||
__typename: "Asset";
|
||||
/**
|
||||
* The id of the asset
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The full name of the asset (e.g: Great British Pound)
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* The precision of the asset
|
||||
*/
|
||||
decimals: number;
|
||||
/**
|
||||
* The total supply of the market
|
||||
*/
|
||||
totalSupply: string;
|
||||
/**
|
||||
* The global reward pool account for this asset
|
||||
*/
|
||||
globalRewardPoolAccount: MarketsQuery_markets_tradableInstrument_instrument_product_settlementAsset_globalRewardPoolAccount | null;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_tradableInstrument_instrument_product {
|
||||
__typename: "Future";
|
||||
/**
|
||||
* RFC3339Nano maturity date of the product
|
||||
*/
|
||||
maturity: string;
|
||||
/**
|
||||
* The name of the asset (string)
|
||||
*/
|
||||
settlementAsset: MarketsQuery_markets_tradableInstrument_instrument_product_settlementAsset;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_tradableInstrument_instrument {
|
||||
__typename: "Instrument";
|
||||
/**
|
||||
* Full and fairly descriptive name for the instrument
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Metadata for this instrument
|
||||
*/
|
||||
metadata: MarketsQuery_markets_tradableInstrument_instrument_metadata;
|
||||
/**
|
||||
* Uniquely identify an instrument accrods all instruments available on Vega (string)
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* A short non necessarily unique code used to easily describe the instrument (e.g: FX:BTCUSD/DEC18) (string)
|
||||
*/
|
||||
code: string;
|
||||
/**
|
||||
* A reference to or instance of a fully specified product, including all required product parameters for that product (Product union)
|
||||
*/
|
||||
product: MarketsQuery_markets_tradableInstrument_instrument_product;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_tradableInstrument_riskModel_LogNormalRiskModel_params {
|
||||
__typename: "LogNormalModelParams";
|
||||
/**
|
||||
* r parameter
|
||||
*/
|
||||
r: number;
|
||||
/**
|
||||
* sigma parameter
|
||||
*/
|
||||
sigma: number;
|
||||
/**
|
||||
* mu parameter
|
||||
*/
|
||||
mu: number;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_tradableInstrument_riskModel_LogNormalRiskModel {
|
||||
__typename: "LogNormalRiskModel";
|
||||
/**
|
||||
* Tau parameter of the risk model
|
||||
*/
|
||||
tau: number;
|
||||
/**
|
||||
* Lambda parameter of the risk model
|
||||
*/
|
||||
riskAversionParameter: number;
|
||||
/**
|
||||
* Params for the log normal risk model
|
||||
*/
|
||||
params: MarketsQuery_markets_tradableInstrument_riskModel_LogNormalRiskModel_params;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_tradableInstrument_riskModel_SimpleRiskModel_params {
|
||||
__typename: "SimpleRiskModelParams";
|
||||
/**
|
||||
* Risk factor for long
|
||||
*/
|
||||
factorLong: number;
|
||||
/**
|
||||
* Risk factor for short
|
||||
*/
|
||||
factorShort: number;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_tradableInstrument_riskModel_SimpleRiskModel {
|
||||
__typename: "SimpleRiskModel";
|
||||
/**
|
||||
* Params for the simple risk model
|
||||
*/
|
||||
params: MarketsQuery_markets_tradableInstrument_riskModel_SimpleRiskModel_params;
|
||||
}
|
||||
|
||||
export type MarketsQuery_markets_tradableInstrument_riskModel = MarketsQuery_markets_tradableInstrument_riskModel_LogNormalRiskModel | MarketsQuery_markets_tradableInstrument_riskModel_SimpleRiskModel;
|
||||
|
||||
export interface MarketsQuery_markets_tradableInstrument_marginCalculator_scalingFactors {
|
||||
__typename: "ScalingFactors";
|
||||
/**
|
||||
* the scaling factor that determines the margin level at which Vega has to search for more money
|
||||
*/
|
||||
searchLevel: number;
|
||||
/**
|
||||
* the scaling factor that determines the optimal margin level
|
||||
*/
|
||||
initialMargin: number;
|
||||
/**
|
||||
* The scaling factor that determines the overflow margin level
|
||||
*/
|
||||
collateralRelease: number;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_tradableInstrument_marginCalculator {
|
||||
__typename: "MarginCalculator";
|
||||
/**
|
||||
* The scaling factors that will be used for margin calculation
|
||||
*/
|
||||
scalingFactors: MarketsQuery_markets_tradableInstrument_marginCalculator_scalingFactors;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_tradableInstrument {
|
||||
__typename: "TradableInstrument";
|
||||
/**
|
||||
* An instance of or reference to a fully specified instrument.
|
||||
*/
|
||||
instrument: MarketsQuery_markets_tradableInstrument_instrument;
|
||||
/**
|
||||
* A reference to a risk model that is valid for the instrument
|
||||
*/
|
||||
riskModel: MarketsQuery_markets_tradableInstrument_riskModel;
|
||||
/**
|
||||
* Margin calculation info, currently only the scaling factors (search, initial, release) for this tradable instrument
|
||||
*/
|
||||
marginCalculator: MarketsQuery_markets_tradableInstrument_marginCalculator | null;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_openingAuction {
|
||||
__typename: "AuctionDuration";
|
||||
/**
|
||||
* Duration of the auction in seconds
|
||||
*/
|
||||
durationSecs: number;
|
||||
/**
|
||||
* Target uncrossing trading volume
|
||||
*/
|
||||
volume: number;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_priceMonitoringSettings_parameters_triggers {
|
||||
__typename: "PriceMonitoringTrigger";
|
||||
/**
|
||||
* Price monitoring projection horizon τ in seconds (> 0).
|
||||
*/
|
||||
horizonSecs: number;
|
||||
/**
|
||||
* Price monitoring probability level p. (>0 and < 1)
|
||||
*/
|
||||
probability: number;
|
||||
/**
|
||||
* Price monitoring auction extension duration in seconds should the price
|
||||
* breach it's theoretical level over the specified horizon at the specified
|
||||
* probability level (> 0)
|
||||
*/
|
||||
auctionExtensionSecs: number;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_priceMonitoringSettings_parameters {
|
||||
__typename: "PriceMonitoringParameters";
|
||||
/**
|
||||
* The list of triggers for this price monitoring
|
||||
*/
|
||||
triggers: MarketsQuery_markets_priceMonitoringSettings_parameters_triggers[] | null;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_priceMonitoringSettings {
|
||||
__typename: "PriceMonitoringSettings";
|
||||
/**
|
||||
* Specified a set of PriceMonitoringParameters to be use for price monitoring purposes
|
||||
*/
|
||||
parameters: MarketsQuery_markets_priceMonitoringSettings_parameters | null;
|
||||
/**
|
||||
* How often (in seconds) the price monitoring bounds should be updated
|
||||
*/
|
||||
updateFrequencySecs: number;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_liquidityMonitoringParameters_targetStakeParameters {
|
||||
__typename: "TargetStakeParameters";
|
||||
/**
|
||||
* Specifies length of time window expressed in seconds for target stake calculation
|
||||
*/
|
||||
timeWindow: number;
|
||||
/**
|
||||
* Specifies scaling factors used in target stake calculation
|
||||
*/
|
||||
scalingFactor: number;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_liquidityMonitoringParameters {
|
||||
__typename: "LiquidityMonitoringParameters";
|
||||
/**
|
||||
* Specifies the triggering ratio for entering liquidity auction
|
||||
*/
|
||||
triggeringRatio: number;
|
||||
/**
|
||||
* Specifies parameters related to target stake calculation
|
||||
*/
|
||||
targetStakeParameters: MarketsQuery_markets_liquidityMonitoringParameters_targetStakeParameters;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_proposal {
|
||||
__typename: "Proposal";
|
||||
/**
|
||||
* Proposal ID that is filled by VEGA once proposal reaches the network
|
||||
*/
|
||||
id: string | null;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_accounts_asset {
|
||||
__typename: "Asset";
|
||||
/**
|
||||
* The id of the asset
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The full name of the asset (e.g: Great British Pound)
|
||||
*/
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_accounts {
|
||||
__typename: "Account";
|
||||
/**
|
||||
* Asset, the 'currency'
|
||||
*/
|
||||
asset: MarketsQuery_markets_accounts_asset;
|
||||
/**
|
||||
* Balance as string - current account balance (approx. as balances can be updated several times per second)
|
||||
*/
|
||||
balance: string;
|
||||
/**
|
||||
* Account type (General, Margin, etc)
|
||||
*/
|
||||
type: AccountType;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_data_priceMonitoringBounds_trigger {
|
||||
__typename: "PriceMonitoringTrigger";
|
||||
/**
|
||||
* Price monitoring auction extension duration in seconds should the price
|
||||
* breach it's theoretical level over the specified horizon at the specified
|
||||
* probability level (> 0)
|
||||
*/
|
||||
auctionExtensionSecs: number;
|
||||
/**
|
||||
* Price monitoring probability level p. (>0 and < 1)
|
||||
*/
|
||||
probability: number;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_data_priceMonitoringBounds {
|
||||
__typename: "PriceMonitoringBounds";
|
||||
/**
|
||||
* Minimum price that isn't currently breaching the specified price monitoring trigger
|
||||
*/
|
||||
minValidPrice: string;
|
||||
/**
|
||||
* Maximum price that isn't currently breaching the specified price monitoring trigger
|
||||
*/
|
||||
maxValidPrice: string;
|
||||
/**
|
||||
* Price monitoring trigger associated with the bounds
|
||||
*/
|
||||
trigger: MarketsQuery_markets_data_priceMonitoringBounds_trigger;
|
||||
/**
|
||||
* Reference price used to calculate the valid price range
|
||||
*/
|
||||
referencePrice: string;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_data_liquidityProviderFeeShare_party {
|
||||
__typename: "Party";
|
||||
/**
|
||||
* Party identifier
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_data_liquidityProviderFeeShare {
|
||||
__typename: "LiquidityProviderFeeShare";
|
||||
/**
|
||||
* The liquidity provider party id
|
||||
*/
|
||||
party: MarketsQuery_markets_data_liquidityProviderFeeShare_party;
|
||||
/**
|
||||
* The share own by this liquidity provider (float)
|
||||
*/
|
||||
equityLikeShare: string;
|
||||
/**
|
||||
* the average entry valuation of the liqidity provider for the market
|
||||
*/
|
||||
averageEntryValuation: string;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets_data {
|
||||
__typename: "MarketData";
|
||||
/**
|
||||
* the mark price (actually an unsgined int)
|
||||
*/
|
||||
markPrice: string;
|
||||
/**
|
||||
* the highest price level on an order book for buy orders.
|
||||
*/
|
||||
bestBidPrice: string;
|
||||
/**
|
||||
* the aggregated volume being bid at the best bid price.
|
||||
*/
|
||||
bestBidVolume: string;
|
||||
/**
|
||||
* the lowest price level on an order book for offer orders.
|
||||
*/
|
||||
bestOfferPrice: string;
|
||||
/**
|
||||
* the aggregated volume being offered at the best offer price.
|
||||
*/
|
||||
bestOfferVolume: string;
|
||||
/**
|
||||
* the highest price level on an order book for buy orders not including pegged orders.
|
||||
*/
|
||||
bestStaticBidPrice: string;
|
||||
/**
|
||||
* the aggregated volume being offered at the best static bid price, excluding pegged orders
|
||||
*/
|
||||
bestStaticBidVolume: string;
|
||||
/**
|
||||
* the lowest price level on an order book for offer orders not including pegged orders.
|
||||
*/
|
||||
bestStaticOfferPrice: string;
|
||||
/**
|
||||
* the aggregated volume being offered at the best static offer price, excluding pegged orders.
|
||||
*/
|
||||
bestStaticOfferVolume: string;
|
||||
/**
|
||||
* the arithmetic average of the best bid price and best offer price.
|
||||
*/
|
||||
midPrice: string;
|
||||
/**
|
||||
* the arithmetic average of the best static bid price and best static offer price
|
||||
*/
|
||||
staticMidPrice: string;
|
||||
/**
|
||||
* RFC3339Nano time at which this market price was releavant
|
||||
*/
|
||||
timestamp: string;
|
||||
/**
|
||||
* the sum of the size of all positions greater than 0.
|
||||
*/
|
||||
openInterest: string;
|
||||
/**
|
||||
* RFC3339Nano time at which the auction will stop (null if not in auction mode)
|
||||
*/
|
||||
auctionEnd: string | null;
|
||||
/**
|
||||
* RFC3339Nano time at which the next auction will start (null if none is scheduled)
|
||||
*/
|
||||
auctionStart: string | null;
|
||||
/**
|
||||
* indicative price if the auction ended now, 0 if not in auction mode
|
||||
*/
|
||||
indicativePrice: string;
|
||||
/**
|
||||
* indicative volume if the auction ended now, 0 if not in auction mode
|
||||
*/
|
||||
indicativeVolume: string;
|
||||
/**
|
||||
* what triggered an auction (if an auction was started)
|
||||
*/
|
||||
trigger: AuctionTrigger;
|
||||
/**
|
||||
* what extended the ongoing auction (if an auction was extended)
|
||||
*/
|
||||
extensionTrigger: AuctionTrigger;
|
||||
/**
|
||||
* the amount of stake targeted for this market
|
||||
*/
|
||||
targetStake: string | null;
|
||||
/**
|
||||
* the supplied stake for the market
|
||||
*/
|
||||
suppliedStake: string | null;
|
||||
/**
|
||||
* A list of valid price ranges per associated trigger
|
||||
*/
|
||||
priceMonitoringBounds: MarketsQuery_markets_data_priceMonitoringBounds[] | null;
|
||||
/**
|
||||
* the market value proxy
|
||||
*/
|
||||
marketValueProxy: string;
|
||||
/**
|
||||
* the equity like share of liquidity fee for each liquidity provider
|
||||
*/
|
||||
liquidityProviderFeeShare: MarketsQuery_markets_data_liquidityProviderFeeShare[] | null;
|
||||
}
|
||||
|
||||
export interface MarketsQuery_markets {
|
||||
__typename: "Market";
|
||||
/**
|
||||
* Market ID
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Market full name
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Fees related data
|
||||
*/
|
||||
fees: MarketsQuery_markets_fees;
|
||||
/**
|
||||
* An instance of or reference to a tradable instrument.
|
||||
*/
|
||||
tradableInstrument: MarketsQuery_markets_tradableInstrument;
|
||||
/**
|
||||
* decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct
|
||||
* number denominated in the currency of the Market. (uint64)
|
||||
*
|
||||
* Examples:
|
||||
* Currency Balance decimalPlaces Real Balance
|
||||
* GBP 100 0 GBP 100
|
||||
* GBP 100 2 GBP 1.00
|
||||
* GBP 100 4 GBP 0.01
|
||||
* GBP 1 4 GBP 0.0001 ( 0.01p )
|
||||
*
|
||||
* GBX (pence) 100 0 GBP 1.00 (100p )
|
||||
* GBX (pence) 100 2 GBP 0.01 ( 1p )
|
||||
* GBX (pence) 100 4 GBP 0.0001 ( 0.01p )
|
||||
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||
*/
|
||||
decimalPlaces: number;
|
||||
/**
|
||||
* Auction duration specifies how long the opening auction will run (minimum
|
||||
* duration and optionally a minimum traded volume).
|
||||
*/
|
||||
openingAuction: MarketsQuery_markets_openingAuction;
|
||||
/**
|
||||
* Price monitoring settings for the market
|
||||
*/
|
||||
priceMonitoringSettings: MarketsQuery_markets_priceMonitoringSettings;
|
||||
/**
|
||||
* Liquidity monitoring parameters for the market
|
||||
*/
|
||||
liquidityMonitoringParameters: MarketsQuery_markets_liquidityMonitoringParameters;
|
||||
/**
|
||||
* Current mode of execution of the market
|
||||
*/
|
||||
tradingMode: MarketTradingMode;
|
||||
/**
|
||||
* Current state of the market
|
||||
*/
|
||||
state: MarketState;
|
||||
/**
|
||||
* The proposal which initiated this market
|
||||
*/
|
||||
proposal: MarketsQuery_markets_proposal | null;
|
||||
/**
|
||||
* Get account for a party or market
|
||||
*/
|
||||
accounts: MarketsQuery_markets_accounts[] | null;
|
||||
/**
|
||||
* marketData for the given market
|
||||
*/
|
||||
data: MarketsQuery_markets_data | null;
|
||||
}
|
||||
|
||||
export interface MarketsQuery {
|
||||
/**
|
||||
* One or more instruments that are trading on the VEGA network
|
||||
*/
|
||||
markets: MarketsQuery_markets[] | null;
|
||||
}
|
154
apps/block-explorer/src/routes/markets/index.tsx
Normal file
154
apps/block-explorer/src/routes/markets/index.tsx
Normal file
@ -0,0 +1,154 @@
|
||||
import { gql, useQuery } from "@apollo/client";
|
||||
import { MarketsQuery } from "./__generated__/MarketsQuery";
|
||||
|
||||
const MARKETS_QUERY = gql`
|
||||
query MarketsQuery {
|
||||
markets {
|
||||
id
|
||||
name
|
||||
fees {
|
||||
factors {
|
||||
makerFee
|
||||
infrastructureFee
|
||||
liquidityFee
|
||||
}
|
||||
}
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
name
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
id
|
||||
code
|
||||
product {
|
||||
... on Future {
|
||||
maturity
|
||||
settlementAsset {
|
||||
id
|
||||
name
|
||||
decimals
|
||||
totalSupply
|
||||
globalRewardPoolAccount {
|
||||
balance
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
riskModel {
|
||||
... on LogNormalRiskModel {
|
||||
tau
|
||||
riskAversionParameter
|
||||
params {
|
||||
r
|
||||
sigma
|
||||
mu
|
||||
}
|
||||
}
|
||||
... on SimpleRiskModel {
|
||||
params {
|
||||
factorLong
|
||||
factorShort
|
||||
}
|
||||
}
|
||||
}
|
||||
marginCalculator {
|
||||
scalingFactors {
|
||||
searchLevel
|
||||
initialMargin
|
||||
collateralRelease
|
||||
}
|
||||
}
|
||||
}
|
||||
decimalPlaces
|
||||
openingAuction {
|
||||
durationSecs
|
||||
volume
|
||||
}
|
||||
priceMonitoringSettings {
|
||||
parameters {
|
||||
triggers {
|
||||
horizonSecs
|
||||
probability
|
||||
auctionExtensionSecs
|
||||
}
|
||||
}
|
||||
updateFrequencySecs
|
||||
}
|
||||
liquidityMonitoringParameters {
|
||||
triggeringRatio
|
||||
targetStakeParameters {
|
||||
timeWindow
|
||||
scalingFactor
|
||||
}
|
||||
}
|
||||
tradingMode
|
||||
state
|
||||
proposal {
|
||||
id
|
||||
}
|
||||
state
|
||||
accounts {
|
||||
asset {
|
||||
id
|
||||
name
|
||||
}
|
||||
balance
|
||||
type
|
||||
}
|
||||
data {
|
||||
markPrice
|
||||
bestBidPrice
|
||||
bestBidVolume
|
||||
bestOfferPrice
|
||||
bestOfferVolume
|
||||
bestStaticBidPrice
|
||||
bestStaticBidVolume
|
||||
bestStaticOfferPrice
|
||||
bestStaticOfferVolume
|
||||
midPrice
|
||||
staticMidPrice
|
||||
timestamp
|
||||
openInterest
|
||||
auctionEnd
|
||||
auctionStart
|
||||
indicativePrice
|
||||
indicativeVolume
|
||||
trigger
|
||||
extensionTrigger
|
||||
targetStake
|
||||
suppliedStake
|
||||
priceMonitoringBounds {
|
||||
minValidPrice
|
||||
maxValidPrice
|
||||
trigger {
|
||||
auctionExtensionSecs
|
||||
probability
|
||||
}
|
||||
referencePrice
|
||||
}
|
||||
marketValueProxy
|
||||
liquidityProviderFeeShare {
|
||||
party {
|
||||
id
|
||||
}
|
||||
equityLikeShare
|
||||
averageEntryValuation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Markets = () => {
|
||||
const { data } = useQuery<MarketsQuery>(MARKETS_QUERY);
|
||||
return (
|
||||
<section>
|
||||
<h1>Markets</h1>
|
||||
<pre>{JSON.stringify(data, null, " ")}</pre>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Markets;
|
27
apps/block-explorer/src/routes/network-parameters/__generated__/NetworkParametersQuery.ts
generated
Normal file
27
apps/block-explorer/src/routes/network-parameters/__generated__/NetworkParametersQuery.ts
generated
Normal file
@ -0,0 +1,27 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: NetworkParametersQuery
|
||||
// ====================================================
|
||||
|
||||
export interface NetworkParametersQuery_networkParameters {
|
||||
__typename: "NetworkParameter";
|
||||
/**
|
||||
* The name of the network parameter
|
||||
*/
|
||||
key: string;
|
||||
/**
|
||||
* The value of the network parameter
|
||||
*/
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface NetworkParametersQuery {
|
||||
/**
|
||||
* return the full list of network parameters
|
||||
*/
|
||||
networkParameters: NetworkParametersQuery_networkParameters[] | null;
|
||||
}
|
23
apps/block-explorer/src/routes/network-parameters/index.tsx
Normal file
23
apps/block-explorer/src/routes/network-parameters/index.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { gql, useQuery } from "@apollo/client";
|
||||
import { NetworkParametersQuery } from "./__generated__/NetworkParametersQuery";
|
||||
|
||||
export const NETWORK_PARAMETERS_QUERY = gql`
|
||||
query NetworkParametersQuery {
|
||||
networkParameters {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const NetworkParameters = () => {
|
||||
const { data } = useQuery<NetworkParametersQuery>(NETWORK_PARAMETERS_QUERY);
|
||||
return (
|
||||
<section>
|
||||
<h1>NetworkParameters</h1>
|
||||
<pre>{JSON.stringify(data, null, " ")}</pre>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default NetworkParameters;
|
15
apps/block-explorer/src/routes/parties/home/index.tsx
Normal file
15
apps/block-explorer/src/routes/parties/home/index.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import React from "react";
|
||||
|
||||
const Parties = () => {
|
||||
return (
|
||||
<section>
|
||||
<h1>Parties</h1>
|
||||
<h2>
|
||||
Not sure what to do with this page? Could show all parties but would
|
||||
eventually need to be rewritten. But that's not very useful either
|
||||
</h2>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export { Parties };
|
125
apps/block-explorer/src/routes/parties/id/__generated__/PartyAssetsQuery.ts
generated
Normal file
125
apps/block-explorer/src/routes/parties/id/__generated__/PartyAssetsQuery.ts
generated
Normal file
@ -0,0 +1,125 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AccountType } from "./../../../../__generated__/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: PartyAssetsQuery
|
||||
// ====================================================
|
||||
|
||||
export interface PartyAssetsQuery_party_delegations_node {
|
||||
__typename: "Node";
|
||||
/**
|
||||
* The node url eg n01.vega.xyz
|
||||
*/
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface PartyAssetsQuery_party_delegations {
|
||||
__typename: "Delegation";
|
||||
/**
|
||||
* Amount delegated
|
||||
*/
|
||||
amount: string;
|
||||
/**
|
||||
* URL of node you are delegating to
|
||||
*/
|
||||
node: PartyAssetsQuery_party_delegations_node;
|
||||
/**
|
||||
* Epoch of delegation
|
||||
*/
|
||||
epoch: number;
|
||||
}
|
||||
|
||||
export interface PartyAssetsQuery_party_stake {
|
||||
__typename: "PartyStake";
|
||||
/**
|
||||
* The stake currently available for the party
|
||||
*/
|
||||
currentStakeAvailable: string;
|
||||
}
|
||||
|
||||
export interface PartyAssetsQuery_party_accounts_asset_source_BuiltinAsset {
|
||||
__typename: "BuiltinAsset";
|
||||
}
|
||||
|
||||
export interface PartyAssetsQuery_party_accounts_asset_source_ERC20 {
|
||||
__typename: "ERC20";
|
||||
/**
|
||||
* The address of the erc20 contract
|
||||
*/
|
||||
contractAddress: string;
|
||||
}
|
||||
|
||||
export type PartyAssetsQuery_party_accounts_asset_source = PartyAssetsQuery_party_accounts_asset_source_BuiltinAsset | PartyAssetsQuery_party_accounts_asset_source_ERC20;
|
||||
|
||||
export interface PartyAssetsQuery_party_accounts_asset {
|
||||
__typename: "Asset";
|
||||
/**
|
||||
* The full name of the asset (e.g: Great British Pound)
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* The id of the asset
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The precision of the asset
|
||||
*/
|
||||
decimals: number;
|
||||
/**
|
||||
* The symbol of the asset (e.g: GBP)
|
||||
*/
|
||||
symbol: string;
|
||||
/**
|
||||
* The origin source of the asset (e.g: an erc20 asset)
|
||||
*/
|
||||
source: PartyAssetsQuery_party_accounts_asset_source;
|
||||
}
|
||||
|
||||
export interface PartyAssetsQuery_party_accounts {
|
||||
__typename: "Account";
|
||||
/**
|
||||
* Asset, the 'currency'
|
||||
*/
|
||||
asset: PartyAssetsQuery_party_accounts_asset;
|
||||
/**
|
||||
* Account type (General, Margin, etc)
|
||||
*/
|
||||
type: AccountType;
|
||||
/**
|
||||
* Balance as string - current account balance (approx. as balances can be updated several times per second)
|
||||
*/
|
||||
balance: string;
|
||||
}
|
||||
|
||||
export interface PartyAssetsQuery_party {
|
||||
__typename: "Party";
|
||||
/**
|
||||
* Party identifier
|
||||
*/
|
||||
id: string;
|
||||
delegations: PartyAssetsQuery_party_delegations[] | null;
|
||||
/**
|
||||
* The staking informations for this Party
|
||||
*/
|
||||
stake: PartyAssetsQuery_party_stake;
|
||||
/**
|
||||
* Collateral accounts relating to a party
|
||||
*/
|
||||
accounts: PartyAssetsQuery_party_accounts[] | null;
|
||||
}
|
||||
|
||||
export interface PartyAssetsQuery {
|
||||
/**
|
||||
* An entity that is trading on the VEGA network
|
||||
*/
|
||||
party: PartyAssetsQuery_party | null;
|
||||
}
|
||||
|
||||
export interface PartyAssetsQueryVariables {
|
||||
partyId: string;
|
||||
}
|
74
apps/block-explorer/src/routes/parties/id/index.tsx
Normal file
74
apps/block-explorer/src/routes/parties/id/index.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { gql } from "@apollo/client";
|
||||
import React from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { DATA_SOURCES } from "../../../config";
|
||||
import useFetch from "../../../hooks/use-fetch";
|
||||
import { TendermintSearchTransactionResponse } from "../tendermint-transaction-response";
|
||||
import {
|
||||
PartyAssetsQuery,
|
||||
PartyAssetsQueryVariables,
|
||||
} from "./__generated__/PartyAssetsQuery";
|
||||
|
||||
const PARTY_ASSETS_QUERY = gql`
|
||||
query PartyAssetsQuery($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
id
|
||||
delegations {
|
||||
amount
|
||||
node {
|
||||
id
|
||||
name
|
||||
}
|
||||
epoch
|
||||
}
|
||||
stake {
|
||||
currentStakeAvailable
|
||||
}
|
||||
accounts {
|
||||
asset {
|
||||
name
|
||||
id
|
||||
decimals
|
||||
symbol
|
||||
source {
|
||||
__typename
|
||||
... on ERC20 {
|
||||
contractAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
type
|
||||
balance
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Party = () => {
|
||||
const { party } = useParams<{ party: string }>();
|
||||
const { data: partyData } = useFetch<TendermintSearchTransactionResponse>(
|
||||
`${DATA_SOURCES.tendermintWebsocketUrl}/tx_search?query="tx.submitter=%27${party}%27"`
|
||||
);
|
||||
|
||||
const { data } = useQuery<PartyAssetsQuery, PartyAssetsQueryVariables>(
|
||||
PARTY_ASSETS_QUERY,
|
||||
{
|
||||
// Don't cache data for this query, party information can move quite quickly
|
||||
fetchPolicy: "network-only",
|
||||
variables: { partyId: party.replace("0x", "") },
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h1>Party</h1>
|
||||
<h2>Tendermint Data</h2>
|
||||
<pre>{JSON.stringify(partyData, null, " ")}</pre>
|
||||
<h2>Asset data</h2>
|
||||
<pre>{JSON.stringify(data, null, " ")}</pre>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export { Party };
|
21
apps/block-explorer/src/routes/parties/index.tsx
Normal file
21
apps/block-explorer/src/routes/parties/index.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import { Route, Switch, useRouteMatch } from "react-router-dom";
|
||||
import { Parties } from "./home";
|
||||
import { Party } from "./id";
|
||||
|
||||
const PartiesPage = () => {
|
||||
const match = useRouteMatch();
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Route path={match.path} exact={true}>
|
||||
<Parties />
|
||||
</Route>
|
||||
<Route path={`${match.path}/:party`}>
|
||||
<Party />
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
export default PartiesPage;
|
40
apps/block-explorer/src/routes/parties/tendermint-transaction-response.d.ts
vendored
Normal file
40
apps/block-explorer/src/routes/parties/tendermint-transaction-response.d.ts
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
export interface Attribute {
|
||||
key: string;
|
||||
value: string;
|
||||
index: boolean;
|
||||
}
|
||||
|
||||
export interface Event {
|
||||
type: string;
|
||||
attributes: Attribute[];
|
||||
}
|
||||
|
||||
export interface TxResult {
|
||||
code: number;
|
||||
data?: any;
|
||||
log: string;
|
||||
info: string;
|
||||
gas_wanted: string;
|
||||
gas_used: string;
|
||||
events: Event[];
|
||||
codespace: string;
|
||||
}
|
||||
|
||||
export interface Tx {
|
||||
hash: string;
|
||||
height: string;
|
||||
index: number;
|
||||
tx_result: TxResult;
|
||||
tx: string;
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
txs: Tx[];
|
||||
total_count: string;
|
||||
}
|
||||
|
||||
export interface TendermintSearchTransactionResponse {
|
||||
jsonrpc: string;
|
||||
id: number;
|
||||
result: Result;
|
||||
}
|
79
apps/block-explorer/src/routes/router-config.ts
Normal file
79
apps/block-explorer/src/routes/router-config.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import Assets from "./assets";
|
||||
import Blocks from "./blocks";
|
||||
import Governance from "./governance";
|
||||
import Home from "./home";
|
||||
import Markets from "./markets";
|
||||
import Party from "./parties";
|
||||
import Txs from "./txs";
|
||||
import Validators from "./validators";
|
||||
import Genesis from "./genesis";
|
||||
import NetworkParameters from "./network-parameters";
|
||||
|
||||
export const Routes = {
|
||||
HOME: "/",
|
||||
TX: "/txs",
|
||||
BLOCKS: "/blocks",
|
||||
PARTIES: "/parties",
|
||||
VALIDATORS: "/validators",
|
||||
ASSETS: "/assets",
|
||||
GENESIS: "/genesis",
|
||||
GOVERNANCE: "/governance",
|
||||
MARKETS: "/markets",
|
||||
NETWORK_PARAMETERS: "/network-parameters",
|
||||
};
|
||||
|
||||
const routerConfig = [
|
||||
{
|
||||
path: Routes.HOME,
|
||||
name: "Home",
|
||||
component: Home,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: Routes.TX,
|
||||
name: "Txs",
|
||||
component: Txs,
|
||||
},
|
||||
{
|
||||
path: Routes.BLOCKS,
|
||||
name: "Blocks",
|
||||
component: Blocks,
|
||||
},
|
||||
{
|
||||
path: Routes.PARTIES,
|
||||
name: "Parties",
|
||||
component: Party,
|
||||
},
|
||||
{
|
||||
path: Routes.ASSETS,
|
||||
name: "Assets",
|
||||
component: Assets,
|
||||
},
|
||||
{
|
||||
path: Routes.GENESIS,
|
||||
name: "Genesis",
|
||||
component: Genesis,
|
||||
},
|
||||
{
|
||||
path: Routes.GOVERNANCE,
|
||||
name: "Governance",
|
||||
component: Governance,
|
||||
},
|
||||
{
|
||||
path: Routes.MARKETS,
|
||||
name: "Markets",
|
||||
component: Markets,
|
||||
},
|
||||
{
|
||||
path: Routes.NETWORK_PARAMETERS,
|
||||
name: "NetworkParameters",
|
||||
component: NetworkParameters,
|
||||
},
|
||||
{
|
||||
path: Routes.VALIDATORS,
|
||||
name: "Validators",
|
||||
component: Validators,
|
||||
},
|
||||
];
|
||||
|
||||
export default routerConfig;
|
28
apps/block-explorer/src/routes/txs/home/index.tsx
Normal file
28
apps/block-explorer/src/routes/txs/home/index.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
import { DATA_SOURCES } from "../../../config";
|
||||
import useFetch from "../../../hooks/use-fetch";
|
||||
import { TendermintUnconfirmedTransactionsResponse } from "../tendermint-unconfirmed-transactions-response.d";
|
||||
|
||||
const Txs = () => {
|
||||
const { data: unconfirmedTransactions } =
|
||||
useFetch<TendermintUnconfirmedTransactionsResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/unconfirmed_txs`
|
||||
);
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h1>Tx</h1>
|
||||
<h2>Unconfirmed transactions</h2>
|
||||
https://lb.testnet.vega.xyz/tm/unconfirmed_txs
|
||||
<br />
|
||||
<div>Number: {unconfirmedTransactions?.result?.n_txs || 0}</div>
|
||||
<br />
|
||||
<div>
|
||||
<br />
|
||||
{JSON.stringify(unconfirmedTransactions, null, " ")}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export { Txs };
|
35
apps/block-explorer/src/routes/txs/id/index.tsx
Normal file
35
apps/block-explorer/src/routes/txs/id/index.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import React from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { DATA_SOURCES } from "../../../config";
|
||||
import useFetch from "../../../hooks/use-fetch";
|
||||
import { ChainExplorerTxResponse } from "../../types/chain-explorer-response";
|
||||
import { TendermintTransactionResponse } from "../tendermint-transaction-response.d";
|
||||
|
||||
const Tx = () => {
|
||||
const { txHash } = useParams<{ txHash: string }>();
|
||||
const { data: transactionData } = useFetch<TendermintTransactionResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/tx?hash=${txHash}`
|
||||
);
|
||||
const { data: decodedData } = useFetch<ChainExplorerTxResponse>(
|
||||
DATA_SOURCES.chainExplorerUrl,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
tx_hash: txHash,
|
||||
node_url: `${DATA_SOURCES.tendermintUrl}/`,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h1>Tx</h1>
|
||||
<h2>Tendermint Data</h2>
|
||||
<pre>{JSON.stringify(transactionData, null, " ")}</pre>
|
||||
<h2>Decoded data</h2>
|
||||
<pre>{JSON.stringify(decodedData, null, " ")}</pre>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export { Tx };
|
21
apps/block-explorer/src/routes/txs/index.tsx
Normal file
21
apps/block-explorer/src/routes/txs/index.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import { Route, Switch, useRouteMatch } from "react-router-dom";
|
||||
import { Txs } from "./home";
|
||||
import { Tx } from "./id";
|
||||
|
||||
const TxPage = () => {
|
||||
const match = useRouteMatch();
|
||||
console.log(match);
|
||||
return (
|
||||
<Switch>
|
||||
<Route path={match.path} exact={true}>
|
||||
<Txs />
|
||||
</Route>
|
||||
<Route path={`${match.path}/:txHash`}>
|
||||
<Tx />
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
export default TxPage;
|
@ -0,0 +1,35 @@
|
||||
export interface Attribute {
|
||||
key: string;
|
||||
value: string;
|
||||
index: boolean;
|
||||
}
|
||||
|
||||
export interface Event {
|
||||
type: string;
|
||||
attributes: Attribute[];
|
||||
}
|
||||
|
||||
export interface TxResult {
|
||||
code: number;
|
||||
data?: any;
|
||||
log: string;
|
||||
info: string;
|
||||
gas_wanted: string;
|
||||
gas_used: string;
|
||||
events: Event[];
|
||||
codespace: string;
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
hash: string;
|
||||
height: string;
|
||||
index: number;
|
||||
tx_result: TxResult;
|
||||
tx: string;
|
||||
}
|
||||
|
||||
export interface TendermintTransactionResponse {
|
||||
jsonrpc: string;
|
||||
id: number;
|
||||
result: Result;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
export interface Result {
|
||||
n_txs: string;
|
||||
total: string;
|
||||
total_bytes: string;
|
||||
txs: string[];
|
||||
}
|
||||
|
||||
export interface TendermintUnconfirmedTransactionsResponse {
|
||||
jsonrpc: string;
|
||||
id: number;
|
||||
result: Result;
|
||||
}
|
8
apps/block-explorer/src/routes/types/chain-explorer-response.d.ts
vendored
Normal file
8
apps/block-explorer/src/routes/types/chain-explorer-response.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
export interface ChainExplorerTxResponse {
|
||||
Type: string;
|
||||
Command: string;
|
||||
Sig: string;
|
||||
PubKey: string;
|
||||
Nonce: number;
|
||||
TxHash: string;
|
||||
}
|
5
apps/block-explorer/src/routes/types/tenderming-error-response.d.ts
vendored
Normal file
5
apps/block-explorer/src/routes/types/tenderming-error-response.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export interface TendermintErrorResponse {
|
||||
id: number;
|
||||
jsonrpc: string;
|
||||
error: string;
|
||||
}
|
83
apps/block-explorer/src/routes/validators/__generated__/NodesQuery.ts
generated
Normal file
83
apps/block-explorer/src/routes/validators/__generated__/NodesQuery.ts
generated
Normal file
@ -0,0 +1,83 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { NodeStatus } from "./../../../__generated__/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: NodesQuery
|
||||
// ====================================================
|
||||
|
||||
export interface NodesQuery_nodes_epochData {
|
||||
__typename: "EpochData";
|
||||
/**
|
||||
* Total number of epochs since node was created
|
||||
*/
|
||||
total: number;
|
||||
/**
|
||||
* Total number of offline epochs since node was created
|
||||
*/
|
||||
offline: number;
|
||||
/**
|
||||
* Total number of online epochs since node was created
|
||||
*/
|
||||
online: number;
|
||||
}
|
||||
|
||||
export interface NodesQuery_nodes {
|
||||
__typename: "Node";
|
||||
/**
|
||||
* The node url eg n01.vega.xyz
|
||||
*/
|
||||
id: string;
|
||||
name: string;
|
||||
/**
|
||||
* URL where I can find out more info on the node. Will this be possible?
|
||||
*/
|
||||
infoUrl: string;
|
||||
avatarUrl: string | null;
|
||||
/**
|
||||
* Pubkey of the node operator
|
||||
*/
|
||||
pubkey: string;
|
||||
/**
|
||||
* Public key of Tendermint
|
||||
*/
|
||||
tmPubkey: string;
|
||||
/**
|
||||
* Ethereum public key of the node
|
||||
*/
|
||||
ethereumAdddress: string;
|
||||
/**
|
||||
* Country code for the location of the node
|
||||
*/
|
||||
location: string;
|
||||
/**
|
||||
* The amount the node has put up themselves
|
||||
*/
|
||||
stakedByOperator: string;
|
||||
/**
|
||||
* The amount of stake that has been delegated by token holders
|
||||
*/
|
||||
stakedByDelegates: string;
|
||||
/**
|
||||
* Total amount staked on node
|
||||
*/
|
||||
stakedTotal: string;
|
||||
/**
|
||||
* Amount of stake on the next epoch
|
||||
*/
|
||||
pendingStake: string;
|
||||
epochData: NodesQuery_nodes_epochData | null;
|
||||
status: NodeStatus;
|
||||
score: string;
|
||||
normalisedScore: string;
|
||||
}
|
||||
|
||||
export interface NodesQuery {
|
||||
/**
|
||||
* all known network nodes
|
||||
*/
|
||||
nodes: NodesQuery_nodes[] | null;
|
||||
}
|
53
apps/block-explorer/src/routes/validators/index.tsx
Normal file
53
apps/block-explorer/src/routes/validators/index.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { gql, useQuery } from "@apollo/client";
|
||||
import React from "react";
|
||||
import { DATA_SOURCES } from "../../config";
|
||||
import useFetch from "../../hooks/use-fetch";
|
||||
import { TendermintValidatorsResponse } from "./tendermint-validator-response";
|
||||
import { NodesQuery } from "./__generated__/NodesQuery";
|
||||
|
||||
const NODES_QUERY = gql`
|
||||
query NodesQuery {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
infoUrl
|
||||
avatarUrl
|
||||
pubkey
|
||||
tmPubkey
|
||||
ethereumAdddress
|
||||
location
|
||||
stakedByOperator
|
||||
stakedByDelegates
|
||||
stakedTotal
|
||||
pendingStake
|
||||
epochData {
|
||||
total
|
||||
offline
|
||||
online
|
||||
}
|
||||
status
|
||||
score
|
||||
normalisedScore
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Validators = () => {
|
||||
const { data: validators } = useFetch<TendermintValidatorsResponse>(
|
||||
`${DATA_SOURCES.tendermintUrl}/validators`
|
||||
);
|
||||
const { data } = useQuery<NodesQuery>(NODES_QUERY);
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h1>Validators</h1>
|
||||
<h2>Tendermint data</h2>
|
||||
<pre>{JSON.stringify(validators, null, " ")}</pre>
|
||||
<h2>Vega data</h2>
|
||||
<pre>{JSON.stringify(data, null, " ")}</pre>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Validators;
|
@ -0,0 +1,24 @@
|
||||
export interface PubKey {
|
||||
type: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface Validator {
|
||||
address: string;
|
||||
pub_key: PubKey;
|
||||
voting_power: string;
|
||||
proposer_priority: string;
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
block_height: string;
|
||||
validators: Validator[];
|
||||
count: string;
|
||||
total: string;
|
||||
}
|
||||
|
||||
export interface TendermintValidatorsResponse {
|
||||
jsonrpc: string;
|
||||
id: number;
|
||||
result: Result;
|
||||
}
|
5
apps/block-explorer/src/setupTests.ts
Normal file
5
apps/block-explorer/src/setupTests.ts
Normal file
@ -0,0 +1,5 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
BIN
apps/block-explorer/src/styles/AlphaLyrae-Medium.woff
Normal file
BIN
apps/block-explorer/src/styles/AlphaLyrae-Medium.woff
Normal file
Binary file not shown.
99
apps/block-explorer/src/styles/_colors.scss
Normal file
99
apps/block-explorer/src/styles/_colors.scss
Normal file
@ -0,0 +1,99 @@
|
||||
/* === BLUEPRINT COLOR OVERRIDES === */
|
||||
$black: #000;
|
||||
$white: #fff;
|
||||
|
||||
$dark-gray1: #1f1f1f;
|
||||
$dark-gray2: #2a2a2a;
|
||||
$dark-gray3: #363636;
|
||||
$dark-gray4: #3f3f3f;
|
||||
$dark-gray5: #494949;
|
||||
|
||||
$gray1: #6e6e6e;
|
||||
$gray2: #848484;
|
||||
$gray3: #999;
|
||||
$gray4: #b5b5b5;
|
||||
$gray5: #cbcbcb;
|
||||
|
||||
$light-gray1: #d7d7d7;
|
||||
$light-gray2: #e0e0e0;
|
||||
$light-gray3: #e7e7e7;
|
||||
$light-gray4: #f0f0f0;
|
||||
$light-gray5: #f8f8f8;
|
||||
|
||||
/* === VEGA COLORS === */
|
||||
|
||||
/*
|
||||
Note: We follow blueprints color naming scheme. https://blueprintjs.com/docs/#core/colors EG:
|
||||
$color1 = Darkest
|
||||
$color2
|
||||
$color3 = Base color
|
||||
$color4
|
||||
$color5 = Lightest
|
||||
*/
|
||||
$vega-pink: #ff2d5e;
|
||||
$vega-green: #00f780;
|
||||
|
||||
$vega-green3: #26ff8a;
|
||||
$vega-red3: #ff261a;
|
||||
$vega-blue3: #48aff0;
|
||||
$vega-yellow3: #daff0d;
|
||||
$vega-orange3: #ff7a1a;
|
||||
$vega-yellow4: #edff22;
|
||||
|
||||
$vega-red1: darken($vega-red3, 38%);
|
||||
$vega-green1: darken($vega-green3, 38%);
|
||||
$vega-yellow1: darken($vega-yellow3, 38%);
|
||||
$vega-orange1: darken($vega-orange3, 38%);
|
||||
|
||||
/* === TEXT COLORS === */
|
||||
$text-color: #c7c7c7;
|
||||
$text-color-inverse: #1a1821;
|
||||
$text-color-deemphasise: #8a9ba8;
|
||||
$text-color-emphasise: #f5f8fa;
|
||||
$text-color-error: $vega-red3;
|
||||
|
||||
/* === BUY/SELL BUTTONS === */
|
||||
$button-sell-hover: #893939;
|
||||
$button-sell-active: #ff5e5e;
|
||||
$button-buy-hover: #0a4023;
|
||||
$button-buy-active: #00ffb2;
|
||||
|
||||
/* === MISC BLUEPRINT COLOR OVERRIDES === */
|
||||
$pt-intent-danger: $vega-red3;
|
||||
|
||||
$input-background: #3f3f3f;
|
||||
|
||||
// App background
|
||||
$pt-dark-app-background-color: $dark-gray2;
|
||||
|
||||
// Card
|
||||
$dark-card-background-color: $dark-gray2;
|
||||
|
||||
// Menu
|
||||
$dark-menu-background-color: $dark-gray2;
|
||||
|
||||
// Navbar
|
||||
$dark-navbar-background-color: $black;
|
||||
|
||||
// Popover
|
||||
$dark-popover-background-color: $dark-gray2;
|
||||
|
||||
//overlay-backdrop
|
||||
.bp3-overlay-backdrop {
|
||||
background-color: rgba(73, 73, 73, 0.7);
|
||||
}
|
||||
|
||||
// Text helpers
|
||||
.text-deemphasise {
|
||||
color: $text-color-deemphasise;
|
||||
}
|
||||
|
||||
.text-error {
|
||||
color: $text-color-error;
|
||||
}
|
||||
|
||||
// hover row
|
||||
$row-hover-background-color: $dark-gray5;
|
||||
|
||||
// backdrop
|
||||
$backdrop-black: rgba(0, 0, 0, 0.6);
|
17
apps/block-explorer/src/styles/_fonts.scss
Normal file
17
apps/block-explorer/src/styles/_fonts.scss
Normal file
@ -0,0 +1,17 @@
|
||||
$font-main: "Helvetica neue", "Helvetica", arial, sans-serif;
|
||||
$font-mono: "Roboto Mono", monospace;
|
||||
$font-alpa-lyrae: AlphaLyrae, "Helvetica neue", "Helvetica", arial,
|
||||
sans-serif;
|
||||
|
||||
.font-main {
|
||||
font-family: $font-main;
|
||||
}
|
||||
|
||||
.font-mono {
|
||||
font-family: $font-mono;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: AlphaLyrae;
|
||||
src: url(./AlphaLyrae-Medium.woff);
|
||||
}
|
6
apps/block-explorer/src/styles/_reset.scss
Normal file
6
apps/block-explorer/src/styles/_reset.scss
Normal file
@ -0,0 +1,6 @@
|
||||
fieldset {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
min-width: 0;
|
||||
}
|
26
apps/block-explorer/tsconfig.json
Normal file
26
apps/block-explorer/tsconfig.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
10761
apps/block-explorer/yarn.lock
Normal file
10761
apps/block-explorer/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user