Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0fc56c750e | ||
|
|
7326015fee |
@@ -26,36 +26,22 @@ export const ProtocolUpgradeInProgressNotification = () => {
|
|||||||
const [nextUpgrade] = useLocalStorageSnapshot(
|
const [nextUpgrade] = useLocalStorageSnapshot(
|
||||||
NEXT_PROTOCOL_UPGRADE_PROPOSAL_SNAPSHOT
|
NEXT_PROTOCOL_UPGRADE_PROPOSAL_SNAPSHOT
|
||||||
);
|
);
|
||||||
|
const { blocksRising, block } = useBlockRising();
|
||||||
const detailsLink = useProtocolUpgradeProposalLink();
|
const detailsLink = useProtocolUpgradeProposalLink();
|
||||||
|
|
||||||
let vegaReleaseTag: string | undefined;
|
let vegaReleaseTag: string | undefined;
|
||||||
let upgradeBlockHeight: string | undefined;
|
let upgradeBlockHeight: string | undefined;
|
||||||
|
|
||||||
const hasData = data && !error;
|
if (error && !data && nextUpgrade && ALLOW_STORED_PROPOSAL_DATA) {
|
||||||
const hasStoredData = nextUpgrade && ALLOW_STORED_PROPOSAL_DATA;
|
|
||||||
|
|
||||||
if (hasData) {
|
|
||||||
// gets tag and height from the data api
|
|
||||||
vegaReleaseTag = data.vegaReleaseTag;
|
|
||||||
upgradeBlockHeight = data.upgradeBlockHeight;
|
|
||||||
} else if (hasStoredData) {
|
|
||||||
// gets tag and height from stored value if data api is unavailable
|
|
||||||
try {
|
try {
|
||||||
const stored = JSON.parse(nextUpgrade) as StoredNextProtocolUpgradeData;
|
const stored = JSON.parse(nextUpgrade) as StoredNextProtocolUpgradeData;
|
||||||
vegaReleaseTag = stored.vegaReleaseTag;
|
vegaReleaseTag = stored.vegaReleaseTag;
|
||||||
upgradeBlockHeight = stored.upgradeBlockHeight;
|
upgradeBlockHeight = stored.upgradeBlockHeight;
|
||||||
} catch {
|
} catch {
|
||||||
// NOOP - could not parse stored data
|
// no op
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasUpgradeInfo = vegaReleaseTag && upgradeBlockHeight;
|
|
||||||
|
|
||||||
const { blocksRising, block } = useBlockRising(
|
|
||||||
// skips querying blocks if there's no upgrade information available
|
|
||||||
!hasUpgradeInfo
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If upgrade is in progress then none of the nodes should produce blocks,
|
* If upgrade is in progress then none of the nodes should produce blocks,
|
||||||
* same should be with the tendermint block info otherwise it's a network
|
* same should be with the tendermint block info otherwise it's a network
|
||||||
@@ -64,7 +50,10 @@ export const ProtocolUpgradeInProgressNotification = () => {
|
|||||||
* Once the networks is back then the notification disappears.
|
* Once the networks is back then the notification disappears.
|
||||||
*/
|
*/
|
||||||
const upgradeInProgress =
|
const upgradeInProgress =
|
||||||
hasUpgradeInfo && !blocksRising && block <= Number(upgradeBlockHeight);
|
vegaReleaseTag &&
|
||||||
|
upgradeBlockHeight &&
|
||||||
|
!blocksRising &&
|
||||||
|
block <= Number(upgradeBlockHeight);
|
||||||
|
|
||||||
if (!upgradeInProgress) return null;
|
if (!upgradeInProgress) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -15,33 +15,31 @@ const CHECK_INTERVAL = 5000; // ms
|
|||||||
*/
|
*/
|
||||||
const ALLOW_STALE = 2; // times -> MAX(this, 1) * CHECK_INTERVAL ~> min check time
|
const ALLOW_STALE = 2; // times -> MAX(this, 1) * CHECK_INTERVAL ~> min check time
|
||||||
|
|
||||||
export const useBlockRising = (skip = false) => {
|
export const useBlockRising = () => {
|
||||||
const [blocksRising, setBlocksRising] = useState(true);
|
const [blocksRising, setBlocksRising] = useState(true);
|
||||||
const [block, setBlock] = useState(0);
|
const [block, setBlock] = useState(0);
|
||||||
const nodes = useEnvironment((state) => state.nodes);
|
const nodes = useEnvironment((state) => state.nodes);
|
||||||
const clients = useMemo(() => {
|
const clients = useMemo(() => {
|
||||||
return nodes.map((n) => {
|
return nodes.map(
|
||||||
if (n && n.length > 0) {
|
(n) =>
|
||||||
const client = createClient({
|
n &&
|
||||||
|
n.length > 0 &&
|
||||||
|
createClient({
|
||||||
url: n,
|
url: n,
|
||||||
cacheConfig: undefined,
|
cacheConfig: undefined,
|
||||||
retry: false,
|
retry: false,
|
||||||
connectToDevTools: false,
|
connectToDevTools: false,
|
||||||
connectToHeaderStore: true,
|
connectToHeaderStore: true,
|
||||||
});
|
})
|
||||||
return client;
|
);
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
});
|
|
||||||
}, [nodes]);
|
}, [nodes]);
|
||||||
|
|
||||||
const { refetch: fetchBlockInfo } = useBlockInfo();
|
const { refetch: fetchBlockInfo } = useBlockInfo();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (skip) return;
|
|
||||||
let stale = 0;
|
let stale = 0;
|
||||||
let prev = 0;
|
let prev = 0;
|
||||||
const check = async () => {
|
const check = async () => {
|
||||||
const queries = clients.map((client) =>
|
const queries = clients.map((client, index) =>
|
||||||
client
|
client
|
||||||
? client
|
? client
|
||||||
.query<BlockStatisticsQuery>({
|
.query<BlockStatisticsQuery>({
|
||||||
@@ -49,16 +47,18 @@ export const useBlockRising = (skip = false) => {
|
|||||||
fetchPolicy: 'network-only',
|
fetchPolicy: 'network-only',
|
||||||
errorPolicy: 'ignore',
|
errorPolicy: 'ignore',
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((err) =>
|
||||||
// NOOP - could not retrieve statistics for that node (network error)
|
Promise.reject(
|
||||||
})
|
`could not retrieve statistics from ${nodes[index]}`
|
||||||
|
)
|
||||||
|
)
|
||||||
: undefined
|
: undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
const blockInfo = await fetchBlockInfo();
|
const blockInfo = await fetchBlockInfo();
|
||||||
const results = (await Promise.allSettled(compact(queries))).map(
|
const results = (await Promise.allSettled(compact(queries))).map(
|
||||||
(res) => {
|
(res) => {
|
||||||
if (res && res.status === 'fulfilled' && res.value) {
|
if (res && res.status === 'fulfilled') {
|
||||||
return res.value.data.statistics;
|
return res.value.data.statistics;
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -86,7 +86,7 @@ export const useBlockRising = (skip = false) => {
|
|||||||
return () => {
|
return () => {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
};
|
};
|
||||||
}, [clients, fetchBlockInfo, blocksRising, nodes, skip]);
|
}, [clients, fetchBlockInfo, blocksRising, nodes]);
|
||||||
|
|
||||||
return { blocksRising, block };
|
return { blocksRising, block };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
|
ExternalLink,
|
||||||
Intent,
|
Intent,
|
||||||
Pill,
|
Pill,
|
||||||
TradingButton,
|
TradingButton,
|
||||||
@@ -39,7 +40,7 @@ import { useVegaWallet } from '../use-vega-wallet';
|
|||||||
import { InjectedConnectorForm } from './injected-connector-form';
|
import { InjectedConnectorForm } from './injected-connector-form';
|
||||||
import { isBrowserWalletInstalled } from '../utils';
|
import { isBrowserWalletInstalled } from '../utils';
|
||||||
import { useIsWalletServiceRunning } from '../use-is-wallet-service-running';
|
import { useIsWalletServiceRunning } from '../use-is-wallet-service-running';
|
||||||
import { useIsSnapRunning } from '../use-is-snap-running';
|
import { SnapStatus, useSnapStatus } from '../use-snap-status';
|
||||||
import { useVegaWalletDialogStore } from './vega-wallet-dialog-store';
|
import { useVegaWalletDialogStore } from './vega-wallet-dialog-store';
|
||||||
|
|
||||||
export const CLOSE_DELAY = 1700;
|
export const CLOSE_DELAY = 1700;
|
||||||
@@ -158,7 +159,7 @@ const ConnectDialogContainer = ({
|
|||||||
appChainId
|
appChainId
|
||||||
);
|
);
|
||||||
|
|
||||||
const isSnapRunning = useIsSnapRunning(
|
const snapStatus = useSnapStatus(
|
||||||
DEFAULT_SNAP_ID,
|
DEFAULT_SNAP_ID,
|
||||||
Boolean(connectors['snap'])
|
Boolean(connectors['snap'])
|
||||||
);
|
);
|
||||||
@@ -183,7 +184,7 @@ const ConnectDialogContainer = ({
|
|||||||
setWalletUrl={setWalletUrl}
|
setWalletUrl={setWalletUrl}
|
||||||
onSelect={handleSelect}
|
onSelect={handleSelect}
|
||||||
isDesktopWalletRunning={isDesktopWalletRunning}
|
isDesktopWalletRunning={isDesktopWalletRunning}
|
||||||
isSnapRunning={isSnapRunning}
|
snapStatus={snapStatus}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</ConnectDialogContent>
|
</ConnectDialogContent>
|
||||||
@@ -198,14 +199,14 @@ const ConnectorList = ({
|
|||||||
walletUrl,
|
walletUrl,
|
||||||
setWalletUrl,
|
setWalletUrl,
|
||||||
isDesktopWalletRunning,
|
isDesktopWalletRunning,
|
||||||
isSnapRunning,
|
snapStatus,
|
||||||
}: {
|
}: {
|
||||||
connectors: Connectors;
|
connectors: Connectors;
|
||||||
onSelect: (type: WalletType) => void;
|
onSelect: (type: WalletType) => void;
|
||||||
walletUrl: string;
|
walletUrl: string;
|
||||||
setWalletUrl: (value: string) => void;
|
setWalletUrl: (value: string) => void;
|
||||||
isDesktopWalletRunning: boolean | null;
|
isDesktopWalletRunning: boolean | null;
|
||||||
isSnapRunning: boolean | null;
|
snapStatus: SnapStatus;
|
||||||
}) => {
|
}) => {
|
||||||
const { pubKey, links } = useVegaWallet();
|
const { pubKey, links } = useVegaWallet();
|
||||||
const title = isBrowserWalletInstalled()
|
const title = isBrowserWalletInstalled()
|
||||||
@@ -249,7 +250,7 @@ const ConnectorList = ({
|
|||||||
</div>
|
</div>
|
||||||
{connectors['snap'] !== undefined ? (
|
{connectors['snap'] !== undefined ? (
|
||||||
<div>
|
<div>
|
||||||
{isSnapRunning ? (
|
{snapStatus === SnapStatus.INSTALLED ? (
|
||||||
<ConnectionOption
|
<ConnectionOption
|
||||||
type="snap"
|
type="snap"
|
||||||
text={
|
text={
|
||||||
@@ -267,22 +268,34 @@ const ConnectorList = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ConnectionOption
|
<>
|
||||||
type="snap"
|
<ConnectionOption
|
||||||
text={
|
type="snap"
|
||||||
<>
|
disabled={snapStatus === SnapStatus.NOT_SUPPORTED}
|
||||||
<div className="flex items-center justify-center w-full h-full text-base gap-1">
|
text={
|
||||||
{t('Install Vega MetaMask Snap')}
|
<>
|
||||||
</div>
|
<div className="flex items-center justify-center w-full h-full text-base gap-1">
|
||||||
<div className="absolute top-0 flex items-center h-8 right-1">
|
{t('Install Vega MetaMask Snap')}
|
||||||
<VegaIcon name={VegaIconNames.METAMASK} size={24} />
|
</div>
|
||||||
</div>
|
<div className="absolute top-0 flex items-center h-8 right-1">
|
||||||
</>
|
<VegaIcon name={VegaIconNames.METAMASK} size={24} />
|
||||||
}
|
</div>
|
||||||
onClick={() => {
|
</>
|
||||||
requestSnap(DEFAULT_SNAP_ID);
|
}
|
||||||
}}
|
onClick={() => {
|
||||||
/>
|
requestSnap(DEFAULT_SNAP_ID);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{snapStatus === SnapStatus.NOT_SUPPORTED ? (
|
||||||
|
<p className="pt-2 text-sm text-default">
|
||||||
|
{t('No MetaMask version that supports snaps detected.')}{' '}
|
||||||
|
{t('Learn more about')}{' '}
|
||||||
|
<ExternalLink href="https://metamask.io/snaps/">
|
||||||
|
MetaMask Snaps
|
||||||
|
</ExternalLink>
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -118,14 +118,10 @@ export const getSnap = async (
|
|||||||
snapId: string,
|
snapId: string,
|
||||||
version?: string
|
version?: string
|
||||||
): Promise<Snap | undefined> => {
|
): Promise<Snap | undefined> => {
|
||||||
try {
|
const snaps = await getSnaps();
|
||||||
const snaps = await getSnaps();
|
return Object.values(snaps).find(
|
||||||
return Object.values(snaps).find(
|
(snap) => snap.id === snapId && (!version || snap.version === version)
|
||||||
(snap) => snap.id === snapId && (!version || snap.version === version)
|
);
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const invokeSnap = async <T>(
|
export const invokeSnap = async <T>(
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { getSnap } from './connectors';
|
|
||||||
|
|
||||||
const INTERVAL = 2_000;
|
|
||||||
|
|
||||||
export const useIsSnapRunning = (snapId: string, shouldCheck: boolean) => {
|
|
||||||
const [running, setRunning] = useState(false);
|
|
||||||
useEffect(() => {
|
|
||||||
if (!shouldCheck) return;
|
|
||||||
|
|
||||||
const checkState = async () => {
|
|
||||||
const snap = await getSnap(snapId);
|
|
||||||
setRunning(!!snap);
|
|
||||||
};
|
|
||||||
|
|
||||||
const i = setInterval(() => {
|
|
||||||
checkState();
|
|
||||||
}, INTERVAL);
|
|
||||||
|
|
||||||
checkState();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
clearInterval(i);
|
|
||||||
};
|
|
||||||
}, [snapId, shouldCheck]);
|
|
||||||
return running;
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { getSnap } from './connectors';
|
||||||
|
|
||||||
|
const INTERVAL = 2_000;
|
||||||
|
|
||||||
|
export enum SnapStatus {
|
||||||
|
NOT_SUPPORTED,
|
||||||
|
INSTALLED,
|
||||||
|
NOT_INSTALLED,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSnapStatus = (snapId: string, shouldCheck: boolean) => {
|
||||||
|
const [status, setStatus] = useState<SnapStatus>(SnapStatus.NOT_INSTALLED);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!shouldCheck) return;
|
||||||
|
|
||||||
|
const checkState = async () => {
|
||||||
|
try {
|
||||||
|
const snap = await getSnap(snapId);
|
||||||
|
setStatus(snap ? SnapStatus.INSTALLED : SnapStatus.NOT_INSTALLED);
|
||||||
|
} catch (err) {
|
||||||
|
setStatus(SnapStatus.NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const i = setInterval(() => {
|
||||||
|
checkState();
|
||||||
|
}, INTERVAL);
|
||||||
|
|
||||||
|
checkState();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearInterval(i);
|
||||||
|
};
|
||||||
|
}, [snapId, shouldCheck]);
|
||||||
|
return status;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user