From 8d6ea15b29333fa3b574ffc88ec2e9c2764495e2 Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Tue, 14 Feb 2023 15:41:12 -0800 Subject: [PATCH] feat: update lp dashboard and multisigner app --- .../src/app/app.tsx | 36 +++++++++++-- .../src/main.tsx | 31 +----------- apps/multisig-signer/.env | 3 ++ apps/multisig-signer/.env.devnet | 4 ++ apps/multisig-signer/.env.mainnet | 2 + apps/multisig-signer/.env.sandbox | 2 + apps/multisig-signer/.env.stagnet3 | 2 + apps/multisig-signer/.env.testnet | 2 + apps/multisig-signer/src/app/app.tsx | 12 ++--- libs/environment/src/hooks/use-environment.ts | 50 +++++++++++++++---- 10 files changed, 95 insertions(+), 49 deletions(-) diff --git a/apps/liquidity-provision-dashboard/src/app/app.tsx b/apps/liquidity-provision-dashboard/src/app/app.tsx index 757b88c0f..357d05186 100644 --- a/apps/liquidity-provision-dashboard/src/app/app.tsx +++ b/apps/liquidity-provision-dashboard/src/app/app.tsx @@ -1,3 +1,5 @@ +import type { InMemoryCacheConfig } from '@apollo/client'; +import { NetworkLoader, useInitializeEnv } from '@vegaprotocol/environment'; import { useRoutes } from 'react-router-dom'; import '../styles.scss'; @@ -5,14 +7,40 @@ import { Navbar } from './components/navbar'; import { routerConfig } from './routes/router-config'; +const cache: InMemoryCacheConfig = { + typePolicies: { + Market: { + merge: true, + }, + Party: { + merge: true, + }, + Query: {}, + Account: { + keyFields: false, + fields: { + balanceFormatted: {}, + }, + }, + Node: { + keyFields: false, + }, + Instrument: { + keyFields: false, + }, + }, +}; const AppRouter = () => useRoutes(routerConfig); export function App() { + useInitializeEnv(); return ( -
- - -
+ +
+ + +
+
); } diff --git a/apps/liquidity-provision-dashboard/src/main.tsx b/apps/liquidity-provision-dashboard/src/main.tsx index addcc9921..7615e405e 100644 --- a/apps/liquidity-provision-dashboard/src/main.tsx +++ b/apps/liquidity-provision-dashboard/src/main.tsx @@ -1,44 +1,15 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; -import { EnvironmentProvider, NetworkLoader } from '@vegaprotocol/environment'; import App from './app/app'; -import type { InMemoryCacheConfig } from '@apollo/client'; const rootElement = document.getElementById('root'); const root = rootElement && createRoot(rootElement); -const cache: InMemoryCacheConfig = { - typePolicies: { - Market: { - merge: true, - }, - Party: { - merge: true, - }, - Query: {}, - Account: { - keyFields: false, - fields: { - balanceFormatted: {}, - }, - }, - Node: { - keyFields: false, - }, - Instrument: { - keyFields: false, - }, - }, -}; root?.render( - - - - - + ); diff --git a/apps/multisig-signer/.env b/apps/multisig-signer/.env index 02483fefb..a8ba60771 100644 --- a/apps/multisig-signer/.env +++ b/apps/multisig-signer/.env @@ -2,3 +2,6 @@ NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json NX_VEGA_NETWORKS='{"TESTNET":"https://multisig-signer.fairground.wtf","MAINNET":"https://multisig-signer.vega.xyz"}' NX_VEGA_ENV=STAGNET3 +NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 +NX_ETHERSCAN_URL=https://sepolia.etherscan.io + diff --git a/apps/multisig-signer/.env.devnet b/apps/multisig-signer/.env.devnet index 4155154bf..9e8692993 100644 --- a/apps/multisig-signer/.env.devnet +++ b/apps/multisig-signer/.env.devnet @@ -3,3 +3,7 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/devnet-network.json NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql NX_VEGA_NETWORKS='{"TESTNET":"https://multisig-signer.fairground.wtf","MAINNET":"https://multisig-signer.vega.xyz"}' NX_VEGA_ENV=DEVNET +NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 +NX_ETHERSCAN_URL=https://sepolia.etherscan.io + + diff --git a/apps/multisig-signer/.env.mainnet b/apps/multisig-signer/.env.mainnet index 59c595f17..551b12bdc 100644 --- a/apps/multisig-signer/.env.mainnet +++ b/apps/multisig-signer/.env.mainnet @@ -3,3 +3,5 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/mainnet-network.json NX_VEGA_URL=https://api.vega.xyz/query NX_VEGA_NETWORKS='{"TESTNET":"https://multisig-signer.fairground.wtf","MAINNET":"https://multisig-signer.vega.xyz"}' NX_VEGA_ENV=MAINNET +NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 +NX_ETHERSCAN_URL=https://etherscan.io \ No newline at end of file diff --git a/apps/multisig-signer/.env.sandbox b/apps/multisig-signer/.env.sandbox index baa7a9415..58dfe9405 100644 --- a/apps/multisig-signer/.env.sandbox +++ b/apps/multisig-signer/.env.sandbox @@ -3,3 +3,5 @@ NX_VEGA_URL=https://api.sandbox.vega.xyz/graphql NX_VEGA_ENV=SANDBOX NX_VEGA_NETWORKS={\"DEVNET\":\"https://dev.token.vega.xyz\",\"STAGNET3\":\"https://stagnet3.token.vega.xyz\",\"STAGNET1\":\"https://stagnet1.token.vega.xyz\",\"TESTNET\":\"https://token.fairground.wtf\",\"MAINNET\":\"https://token.vega.xyz\"} NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/sandbox-network.json +NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 +NX_ETHERSCAN_URL=https://sepolia.etherscan.io diff --git a/apps/multisig-signer/.env.stagnet3 b/apps/multisig-signer/.env.stagnet3 index 93045d219..593e9c1bc 100644 --- a/apps/multisig-signer/.env.stagnet3 +++ b/apps/multisig-signer/.env.stagnet3 @@ -3,3 +3,5 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql NX_VEGA_NETWORKS='{"TESTNET":"https://multisig-signer.fairground.wtf","MAINNET":"https://multisig-signer.vega.xyz"}' NX_VEGA_ENV=STAGNET3 +NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 +NX_ETHERSCAN_URL=https://sepolia.etherscan.io \ No newline at end of file diff --git a/apps/multisig-signer/.env.testnet b/apps/multisig-signer/.env.testnet index ae63ae5af..1720077f4 100644 --- a/apps/multisig-signer/.env.testnet +++ b/apps/multisig-signer/.env.testnet @@ -3,3 +3,5 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json NX_VEGA_URL=https://api.n09.testnet.vega.xyz/graphql NX_VEGA_NETWORKS='{"TESTNET":"https://multisig-signer.fairground.wtf","MAINNET":"https://multisig-signer.vega.xyz"}' NX_VEGA_ENV=TESTNET +NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 +NX_ETHERSCAN_URL=https://sepolia.etherscan.io \ No newline at end of file diff --git a/apps/multisig-signer/src/app/app.tsx b/apps/multisig-signer/src/app/app.tsx index f20c6abbe..4707f6f50 100644 --- a/apps/multisig-signer/src/app/app.tsx +++ b/apps/multisig-signer/src/app/app.tsx @@ -3,9 +3,9 @@ import classnames from 'classnames'; import { useEffect, useMemo, useState } from 'react'; import { BrowserTracing } from '@sentry/tracing'; import { - EnvironmentProvider, NetworkLoader, useEnvironment, + useInitializeEnv, } from '@vegaprotocol/environment'; import { AsyncRenderer, Button, Lozenge } from '@vegaprotocol/ui-toolkit'; import type { EthereumConfig } from '@vegaprotocol/web3'; @@ -64,6 +64,7 @@ function App() { environment: VEGA_ENV, }); }, [VEGA_ENV]); + const Connectors = useMemo(() => { if (config?.chain_id) { return createConnectors(ETHEREUM_PROVIDER_URL, Number(config.chain_id)); @@ -107,12 +108,11 @@ const Wrapper = () => { }, }, }; + useInitializeEnv(); return ( - - - - - + + + ); }; diff --git a/libs/environment/src/hooks/use-environment.ts b/libs/environment/src/hooks/use-environment.ts index 8a56e0cfd..418466f81 100644 --- a/libs/environment/src/hooks/use-environment.ts +++ b/libs/environment/src/hooks/use-environment.ts @@ -44,6 +44,7 @@ export const useEnvironment = create((set, get) => ({ initialize: async () => { set({ status: 'pending' }); + // validate env vars try { const rawVars = compileEnvVars(); const safeVars = envSchema.parse(rawVars); @@ -70,9 +71,7 @@ export const useEnvironment = create((set, get) => ({ console.warn(`Could not fetch node config from ${state.VEGA_CONFIG_URL}`); } - // user has previously loaded the app and found - // a successful node, or chosen one manually - reconnect - // to same node + // Node url found in localStorage, if its valid attempt to connect if (storedUrl) { if (isValidUrl(storedUrl)) { set({ VEGA_URL: storedUrl, status: 'success' }); @@ -82,12 +81,14 @@ export const useEnvironment = create((set, get) => ({ } } - // VEGA_URL env var is set no need to find suitable node + // VEGA_URL env var is set and is a valid url no need to proceed if (state.VEGA_URL) { set({ status: 'success' }); return; } + // No url found in env vars or localStorage, AND no nodes were found in + // the config fetched from VEGA_CONFIG_URL, app initialization has failed if (!nodes || !nodes.length) { set({ status: 'failed', @@ -96,7 +97,7 @@ export const useEnvironment = create((set, get) => ({ return; } - // create client and store instances + // Create a map of node urls to client instances const clients: ClientCollection = {}; nodes.forEach((url) => { clients[url] = createClient({ @@ -107,7 +108,8 @@ export const useEnvironment = create((set, get) => ({ }); }); - // find a suitable node to connected, first one to respond is chosen + // Find a suitable node to connect to by attempting a query and a + // subscription, first to fulfill both will be the resulting url. const url = await findNode(clients); if (url !== null) { @@ -116,7 +118,10 @@ export const useEnvironment = create((set, get) => ({ VEGA_URL: url, }); LocalStorage.setItem(STORAGE_KEY, url); - } else { + } + // Every node failed either to make a query or retrieve data from + // a subscription + else { set({ status: 'failed', error: t('No node found'), @@ -126,8 +131,13 @@ export const useEnvironment = create((set, get) => ({ }, })); -// Use this to fetch node config and find suitable node -// if no NX_VEGA_URL is not provided +/** + * Initialize Vega app to dynamically select a node from the + * VEGA_CONFIG_URL + * + * This can be ommitted if you intend to only use a single node, + * in those cases be sure to set NX_VEGA_URL + */ export const useInitializeEnv = () => { const { initialize, status } = useEnvironment((store) => ({ status: store.status, @@ -141,6 +151,9 @@ export const useInitializeEnv = () => { }, [status, initialize]); }; +/** + * Fetch and validate a vega node configuration + */ const fetchConfig = async (url?: string) => { if (!url) return []; const res = await fetch(url); @@ -149,11 +162,18 @@ const fetchConfig = async (url?: string) => { return result.hosts; }; +/** + * Find a suitable node by running a test query and test + * subscription, against a list of clients, first to resolve wins + */ const findNode = (clients: ClientCollection): Promise => { const tests = Object.entries(clients).map((args) => testNode(...args)); return Promise.race(tests); }; +/** + * Test a node for suitability for connection + */ const testNode = async ( url: string, client: Client @@ -173,6 +193,9 @@ const testNode = async ( } }; +/** + * Run a test query on a client + */ const testQuery = async (client: Client) => { try { const result = await client.query({ @@ -187,6 +210,11 @@ const testQuery = async (client: Client) => { } }; +/** + * Run a test subscription on a client. A subscription + * that takes longer than SUBSCRIPTION_TIMEOUT ms to respond + * is deemed a failure + */ const testSubscription = (client: Client) => { return new Promise((resolve) => { const sub = client @@ -212,6 +240,10 @@ const testSubscription = (client: Client) => { }); }; +/** + * Retrieve env vars, parsing where needed some type casting is needed + * here to appease the environment store interface + */ function compileEnvVars() { const env = { VEGA_URL: process.env['NX_VEGA_URL'],