chore(environment): etherscan link (#3193)

This commit is contained in:
Art 2023-03-15 09:24:20 +01:00 committed by GitHub
parent 66a85cce2a
commit f407110e95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 91 additions and 125 deletions

View File

@ -21,7 +21,7 @@ import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
import { PageTitle } from '../../components/page-helpers/page-title'; import { PageTitle } from '../../components/page-helpers/page-title';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { import {
ContractAddressLink, EtherscanLink,
DApp, DApp,
TOKEN_VALIDATOR, TOKEN_VALIDATOR,
useLinks, useLinks,
@ -224,7 +224,7 @@ export const ValidatorsPage = () => {
<KeyValueTableRow> <KeyValueTableRow>
<div>{t('Ethereum address')}</div> <div>{t('Ethereum address')}</div>
<div className="break-all text-xs"> <div className="break-all text-xs">
<ContractAddressLink address={v.ethereumAddress} />{' '} <EtherscanLink address={v.ethereumAddress} />{' '}
<CopyWithTooltip text={v.ethereumAddress}> <CopyWithTooltip text={v.ethereumAddress}>
<button title={t('Copy address to clipboard')}> <button title={t('Copy address to clipboard')}>
<Icon size={3} name="duplicate" /> <Icon size={3} name="duplicate" />

View File

@ -1,7 +1,6 @@
import { import {
KeyValueTable, KeyValueTable,
KeyValueTableRow, KeyValueTableRow,
Link,
RoundedWrapper, RoundedWrapper,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import { Link as RouterLink } from 'react-router-dom'; import { Link as RouterLink } from 'react-router-dom';
@ -11,7 +10,7 @@ import { useParams } from 'react-router';
import { Navigate } from 'react-router-dom'; import { Navigate } from 'react-router-dom';
import { formatNumber } from '@vegaprotocol/utils'; import { formatNumber } from '@vegaprotocol/utils';
import { useEnvironment } from '@vegaprotocol/environment'; import { EtherscanLink } from '@vegaprotocol/environment';
import { TrancheItem } from '../redemption/tranche-item'; import { TrancheItem } from '../redemption/tranche-item';
import Routes from '../routes'; import Routes from '../routes';
import { TrancheLabel } from './tranche-label'; import { TrancheLabel } from './tranche-label';
@ -19,7 +18,6 @@ import { useTranches } from '../../lib/tranches/tranches-store';
export const Tranche = () => { export const Tranche = () => {
const tranches = useTranches((state) => state.tranches); const tranches = useTranches((state) => state.tranches);
const { ETHERSCAN_URL } = useEnvironment();
const { t } = useTranslation(); const { t } = useTranslation();
const { trancheId } = useParams<{ trancheId: string; address: string }>(); const { trancheId } = useParams<{ trancheId: string; address: string }>();
const { chainId } = useWeb3React(); const { chainId } = useWeb3React();
@ -59,16 +57,7 @@ export const Tranche = () => {
</KeyValueTableRow> </KeyValueTableRow>
{tranche.users.map((user) => ( {tranche.users.map((user) => (
<KeyValueTableRow key={user}> <KeyValueTableRow key={user}>
{ <EtherscanLink address={user} data-testid="link" />
<Link
title={t('View on Etherscan (opens in a new tab)')}
href={`${ETHERSCAN_URL}/address/${user}`}
target="_blank"
>
{user}
</Link>
}
{
<RouterLink <RouterLink
className="underline" className="underline"
title={t('View vesting information')} title={t('View vesting information')}
@ -77,7 +66,6 @@ export const Tranche = () => {
> >
{t('View vesting information')} {t('View vesting information')}
</RouterLink> </RouterLink>
}
</KeyValueTableRow> </KeyValueTableRow>
))} ))}
</KeyValueTable> </KeyValueTable>

View File

@ -1,6 +1,6 @@
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { useAssetsDataProvider } from '@vegaprotocol/assets'; import { useAssetsDataProvider } from '@vegaprotocol/assets';
import { ETHERSCAN_TX, useEtherscanLink } from '@vegaprotocol/environment'; import { EtherscanLink } from '@vegaprotocol/environment';
import { formatNumber, toBigNum } from '@vegaprotocol/utils'; import { formatNumber, toBigNum } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import type { Toast, ToastContent } from '@vegaprotocol/ui-toolkit'; import type { Toast, ToastContent } from '@vegaprotocol/ui-toolkit';
@ -8,7 +8,7 @@ import { ToastHeading } from '@vegaprotocol/ui-toolkit';
import { Panel } from '@vegaprotocol/ui-toolkit'; import { Panel } from '@vegaprotocol/ui-toolkit';
import { CLOSE_AFTER } from '@vegaprotocol/ui-toolkit'; import { CLOSE_AFTER } from '@vegaprotocol/ui-toolkit';
import { useToasts } from '@vegaprotocol/ui-toolkit'; import { useToasts } from '@vegaprotocol/ui-toolkit';
import { ExternalLink, Intent, ProgressBar } from '@vegaprotocol/ui-toolkit'; import { Intent, ProgressBar } from '@vegaprotocol/ui-toolkit';
import { useCallback } from 'react'; import { useCallback } from 'react';
import compact from 'lodash/compact'; import compact from 'lodash/compact';
import type { EthStoredTxState } from '@vegaprotocol/web3'; import type { EthStoredTxState } from '@vegaprotocol/web3';
@ -103,7 +103,7 @@ const EthTxPendingToastContent = ({ tx }: EthTxToastContentProps) => {
<> <>
<ToastHeading>{t('Awaiting confirmation')}</ToastHeading> <ToastHeading>{t('Awaiting confirmation')}</ToastHeading>
<p>{t('Please wait for your transaction to be confirmed.')}</p> <p>{t('Please wait for your transaction to be confirmed.')}</p>
<EtherscanLink tx={tx} /> {tx.txHash && <EtherscanLink tx={tx.txHash} />}
<EthTransactionDetails tx={tx} /> <EthTransactionDetails tx={tx} />
</> </>
); );
@ -126,26 +126,12 @@ const EthTxErrorToastContent = ({ tx }: EthTxToastContentProps) => {
); );
}; };
const EtherscanLink = ({ tx }: EthTxToastContentProps) => {
const etherscanLink = useEtherscanLink();
return tx.txHash ? (
<p className="break-all">
<ExternalLink
href={etherscanLink(ETHERSCAN_TX.replace(':hash', tx.txHash))}
rel="noreferrer"
>
{t('View on Etherscan')}
</ExternalLink>
</p>
) : null;
};
const EthTxConfirmedToastContent = ({ tx }: EthTxToastContentProps) => { const EthTxConfirmedToastContent = ({ tx }: EthTxToastContentProps) => {
return ( return (
<> <>
<ToastHeading>{t('Transaction confirmed')}</ToastHeading> <ToastHeading>{t('Transaction confirmed')}</ToastHeading>
<p>{t('Your transaction has been confirmed.')}</p> <p>{t('Your transaction has been confirmed.')}</p>
<EtherscanLink tx={tx} /> {tx.txHash && <EtherscanLink tx={tx.txHash} />}
<EthTransactionDetails tx={tx} /> <EthTransactionDetails tx={tx} />
</> </>
); );
@ -162,7 +148,7 @@ const EthTxCompletedToastContent = ({ tx }: EthTxToastContentProps) => {
{t('Your transaction has been completed.')}{' '} {t('Your transaction has been completed.')}{' '}
{isDeposit && t('Waiting for deposit confirmation.')} {isDeposit && t('Waiting for deposit confirmation.')}
</p> </p>
<EtherscanLink tx={tx} /> {tx.txHash && <EtherscanLink tx={tx.txHash} />}
<EthTransactionDetails tx={tx} /> <EthTransactionDetails tx={tx} />
</> </>
); );

View File

@ -1,4 +1,4 @@
import { ContractAddressLink } from '@vegaprotocol/environment'; import { EtherscanLink } from '@vegaprotocol/environment';
import { addDecimalsFormatNumber } from '@vegaprotocol/utils'; import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import type * as Schema from '@vegaprotocol/types'; import type * as Schema from '@vegaprotocol/types';
@ -108,7 +108,7 @@ export const rows: Rows = [
return ( return (
<> <>
<ContractAddressLink address={asset.source.contractAddress} />{' '} <EtherscanLink address={asset.source.contractAddress} />{' '}
<CopyWithTooltip text={asset.source.contractAddress}> <CopyWithTooltip text={asset.source.contractAddress}>
<button title={t('Copy address to clipboard')}> <button title={t('Copy address to clipboard')}>
<Icon size={3} name="duplicate" /> <Icon size={3} name="duplicate" />

View File

@ -1,7 +1,7 @@
import type { Asset } from '@vegaprotocol/assets'; import type { Asset } from '@vegaprotocol/assets';
import { useEnvironment } from '@vegaprotocol/environment'; import { EtherscanLink } from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { ExternalLink, Intent, Notification } from '@vegaprotocol/ui-toolkit'; import { Intent, Notification } from '@vegaprotocol/ui-toolkit';
import { formatNumber } from '@vegaprotocol/utils'; import { formatNumber } from '@vegaprotocol/utils';
import type { EthStoredTxState } from '@vegaprotocol/web3'; import type { EthStoredTxState } from '@vegaprotocol/web3';
import { EthTxStatus, useEthTransactionStore } from '@vegaprotocol/web3'; import { EthTxStatus, useEthTransactionStore } from '@vegaprotocol/web3';
@ -126,14 +126,10 @@ const ApprovalTxFeedback = ({
selectedAsset: Asset; selectedAsset: Asset;
allowance?: BigNumber; allowance?: BigNumber;
}) => { }) => {
const { ETHERSCAN_URL } = useEnvironment();
if (!tx) return null; if (!tx) return null;
const txLink = tx.txHash && ( const txLink = tx.txHash && (
<ExternalLink href={`${ETHERSCAN_URL}/tx/${tx.txHash}`}> <EtherscanLink tx={tx.txHash}>{t('View on Etherscan')}</EtherscanLink>
{t('View on Etherscan')}
</ExternalLink>
); );
if (tx.status === EthTxStatus.Error) { if (tx.status === EthTxStatus.Error) {

View File

@ -8,7 +8,6 @@ import {
} from '@vegaprotocol/utils'; } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import { Link } from '@vegaprotocol/ui-toolkit';
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid'; import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
import type { import type {
VegaICellRendererParams, VegaICellRendererParams,
@ -16,14 +15,13 @@ import type {
TypedDataAgGrid, TypedDataAgGrid,
} from '@vegaprotocol/datagrid'; } from '@vegaprotocol/datagrid';
import type { DepositFieldsFragment } from './__generated__/Deposit'; import type { DepositFieldsFragment } from './__generated__/Deposit';
import { useEnvironment } from '@vegaprotocol/environment'; import { EtherscanLink } from '@vegaprotocol/environment';
import { DepositStatusMapping } from '@vegaprotocol/types'; import { DepositStatusMapping } from '@vegaprotocol/types';
export const DepositsTable = forwardRef< export const DepositsTable = forwardRef<
AgGridReact, AgGridReact,
TypedDataAgGrid<DepositFieldsFragment> TypedDataAgGrid<DepositFieldsFragment>
>((props, ref) => { >((props, ref) => {
const { ETHERSCAN_URL } = useEnvironment();
return ( return (
<AgGrid <AgGrid
ref={ref} ref={ref}
@ -77,14 +75,9 @@ export const DepositsTable = forwardRef<
if (!data) return null; if (!data) return null;
if (!value) return '-'; if (!value) return '-';
return ( return (
<Link <EtherscanLink tx={value} data-testid="etherscan-link">
title={t('View transaction on Etherscan')}
href={`${ETHERSCAN_URL}/tx/${value}`}
data-testid="etherscan-link"
target="_blank"
>
{truncateByChars(value)} {truncateByChars(value)}
</Link> </EtherscanLink>
); );
}} }}
/> />

View File

@ -1,7 +1,7 @@
import type { Asset } from '@vegaprotocol/assets'; import type { Asset } from '@vegaprotocol/assets';
import { useEnvironment } from '@vegaprotocol/environment'; import { EtherscanLink } from '@vegaprotocol/environment';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { ExternalLink, Intent, Notification } from '@vegaprotocol/ui-toolkit'; import { Intent, Notification } from '@vegaprotocol/ui-toolkit';
import { EthTxStatus, useEthTransactionStore } from '@vegaprotocol/web3'; import { EthTxStatus, useEthTransactionStore } from '@vegaprotocol/web3';
import { getFaucetError } from './get-faucet-error'; import { getFaucetError } from './get-faucet-error';
@ -19,7 +19,6 @@ export const FaucetNotification = ({
selectedAsset, selectedAsset,
faucetTxId, faucetTxId,
}: FaucetNotificationProps) => { }: FaucetNotificationProps) => {
const { ETHERSCAN_URL } = useEnvironment();
const tx = useEthTransactionStore((state) => { const tx = useEthTransactionStore((state) => {
return state.transactions.find((t) => t?.id === faucetTxId); return state.transactions.find((t) => t?.id === faucetTxId);
}); });
@ -79,9 +78,9 @@ export const FaucetNotification = ({
</p> </p>
{tx.txHash && ( {tx.txHash && (
<p> <p>
<ExternalLink href={`${ETHERSCAN_URL}/tx/${tx.txHash}`}> <EtherscanLink tx={tx.txHash}>
{t('View on Etherscan')} {t('View on Etherscan')}
</ExternalLink> </EtherscanLink>
</p> </p>
)} )}
</> </>
@ -107,9 +106,9 @@ export const FaucetNotification = ({
</p> </p>
{tx.txHash && ( {tx.txHash && (
<p> <p>
<ExternalLink href={`${ETHERSCAN_URL}/tx/${tx.txHash}`}> <EtherscanLink tx={tx.txHash}>
{t('View on Etherscan')} {t('View on Etherscan')}
</ExternalLink> </EtherscanLink>
</p> </p>
)} )}
</> </>

View File

@ -1,13 +0,0 @@
import { t } from '@vegaprotocol/i18n';
import { Link } from '@vegaprotocol/ui-toolkit';
import { useEtherscanLink } from '../hooks';
export const ContractAddressLink = ({ address }: { address: string }) => {
const etherscanLink = useEtherscanLink();
const href = etherscanLink(`/address/${address}`);
return (
<Link href={href} target="_blank" title={t('View on etherscan')}>
{address}
</Link>
);
};

View File

@ -0,0 +1,38 @@
import { t } from '@vegaprotocol/i18n';
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
import type { ComponentProps } from 'react';
import { ETHERSCAN_ADDRESS, ETHERSCAN_TX, useEtherscanLink } from '../hooks';
export const EtherscanLink = ({
address,
tx,
children,
...props
}: {
address?: string;
tx?: string;
} & ComponentProps<typeof ExternalLink>) => {
const etherscanLink = useEtherscanLink();
let href = '';
if ((!address && !tx) || (address && tx)) {
return null;
}
if (address) {
href = etherscanLink(ETHERSCAN_ADDRESS.replace(':hash', address));
}
if (tx) {
href = etherscanLink(ETHERSCAN_TX.replace(':hash', tx));
}
return (
<ExternalLink
href={href}
title={t('View on Etherscan (opens in a new tab)')}
{...props}
>
{children || address || tx}
</ExternalLink>
);
};

View File

@ -2,4 +2,4 @@ export * from './network-loader';
export * from './network-switcher'; export * from './network-switcher';
export * from './node-guard'; export * from './node-guard';
export * from './node-switcher'; export * from './node-switcher';
export * from './contract-address-link'; export * from './etherscan-link';

View File

@ -103,6 +103,7 @@ export const TOKEN_VALIDATOR = '/validators/:id';
export const EXPLORER_TX = '/txs/:hash'; export const EXPLORER_TX = '/txs/:hash';
// Etherscan pages // Etherscan pages
export const ETHERSCAN_ADDRESS = '/address/:hash';
export const ETHERSCAN_TX = '/tx/:hash'; export const ETHERSCAN_TX = '/tx/:hash';
// Console pages // Console pages

View File

@ -1,6 +1,6 @@
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { Link } from '@vegaprotocol/ui-toolkit'; import { Link } from '@vegaprotocol/ui-toolkit';
import { useEnvironment } from '@vegaprotocol/environment'; import { EtherscanLink, useEnvironment } from '@vegaprotocol/environment';
import { EthTxStatus } from '../use-ethereum-transaction'; import { EthTxStatus } from '../use-ethereum-transaction';
const ACTIVE_CLASSES = 'text-black dark:text-white'; const ACTIVE_CLASSES = 'text-black dark:text-white';
@ -62,14 +62,14 @@ export const TxRow = ({
}`} }`}
> >
<span>{t('Ethereum transaction complete')}</span> <span>{t('Ethereum transaction complete')}</span>
<Link {txHash && (
href={`${ETHERSCAN_URL}/tx/${txHash}`} <EtherscanLink
title={t('View on Etherscan')} tx={txHash}
className="text-vega-pink dark:text-vega-yellow" className="text-vega-pink dark:text-vega-yellow"
target="_blank"
> >
{t('View transaction on Etherscan')} {t('View transaction on Etherscan')}
</Link> </EtherscanLink>
)}
</p> </p>
); );
} }

View File

@ -9,14 +9,14 @@ import {
} from '@vegaprotocol/utils'; } from '@vegaprotocol/utils';
import { useBottomPlaceholder } from '@vegaprotocol/react-helpers'; import { useBottomPlaceholder } from '@vegaprotocol/react-helpers';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { Link, ButtonLink } from '@vegaprotocol/ui-toolkit'; import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid'; import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
import type { import type {
TypedDataAgGrid, TypedDataAgGrid,
VegaICellRendererParams, VegaICellRendererParams,
VegaValueFormatterParams, VegaValueFormatterParams,
} from '@vegaprotocol/datagrid'; } from '@vegaprotocol/datagrid';
import { useEnvironment } from '@vegaprotocol/environment'; import { EtherscanLink } from '@vegaprotocol/environment';
import type { WithdrawalFieldsFragment } from './__generated__/Withdrawal'; import type { WithdrawalFieldsFragment } from './__generated__/Withdrawal';
import { useEthWithdrawApprovalsStore } from '@vegaprotocol/web3'; import { useEthWithdrawApprovalsStore } from '@vegaprotocol/web3';
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
@ -27,7 +27,6 @@ export const WithdrawalsTable = (
props: TypedDataAgGrid<WithdrawalFieldsFragment> props: TypedDataAgGrid<WithdrawalFieldsFragment>
) => { ) => {
const gridRef = useRef<AgGridReact | null>(null); const gridRef = useRef<AgGridReact | null>(null);
const { ETHERSCAN_URL } = useEnvironment();
const createWithdrawApproval = useEthWithdrawApprovalsStore( const createWithdrawApproval = useEthWithdrawApprovalsStore(
(store) => store.create (store) => store.create
); );
@ -66,7 +65,6 @@ export const WithdrawalsTable = (
headerName={t('Recipient')} headerName={t('Recipient')}
field="details.receiverAddress" field="details.receiverAddress"
cellRenderer="RecipientCell" cellRenderer="RecipientCell"
cellRendererParams={{ ethUrl: ETHERSCAN_URL }}
valueFormatter={({ valueFormatter={({
value, value,
data, data,
@ -126,7 +124,6 @@ export const WithdrawalsTable = (
complete: (withdrawal: WithdrawalFieldsFragment) => { complete: (withdrawal: WithdrawalFieldsFragment) => {
createWithdrawApproval(withdrawal); createWithdrawApproval(withdrawal);
}, },
ethUrl: ETHERSCAN_URL,
}} }}
cellRendererSelector={({ cellRendererSelector={({
data, data,
@ -160,20 +157,12 @@ export const CompleteCell = ({ data, complete }: CompleteCellProps) => {
export const EtherscanLinkCell = ({ export const EtherscanLinkCell = ({
value, value,
ethUrl, }: VegaValueFormatterParams<WithdrawalFieldsFragment, 'txHash'>) => {
}: VegaValueFormatterParams<WithdrawalFieldsFragment, 'txHash'> & {
ethUrl: string;
}) => {
if (!value) return '-'; if (!value) return '-';
return ( return (
<Link <EtherscanLink tx={value} data-testid="etherscan-link">
title={t('View transaction on Etherscan')}
href={`${ethUrl}/tx/${value}`}
data-testid="etherscan-link"
target="_blank"
>
{truncateByChars(value)} {truncateByChars(value)}
</Link> </EtherscanLink>
); );
}; };
@ -193,28 +182,17 @@ export const StatusCell = ({ data }: { data: WithdrawalFieldsFragment }) => {
return <span>{t('Failed')}</span>; return <span>{t('Failed')}</span>;
}; };
export interface RecipientCellProps
extends VegaICellRendererParams<
WithdrawalFieldsFragment,
'details.receiverAddress'
> {
ethUrl: string;
}
const RecipientCell = ({ const RecipientCell = ({
ethUrl,
value, value,
valueFormatted, valueFormatted,
}: RecipientCellProps) => { }: VegaICellRendererParams<
WithdrawalFieldsFragment,
'details.receiverAddress'
>) => {
return ( return (
<Link <EtherscanLink address={value} data-testid="etherscan-link">
title={t('View on Etherscan (opens in a new tab)')}
href={`${ethUrl}/address/${value}`}
data-testid="etherscan-link"
target="_blank"
>
{valueFormatted} {valueFormatted}
</Link> </EtherscanLink>
); );
}; };