vega-frontend-monorepo/apps/trading/components/web3-container/web3-container.tsx
Matthew Russell f244cd07d4
Feat/103 deposits (#143)
* add web3 provider using web3-react package

* add env setup, add guard for incorrect chain id

* add lib for web3-provider

* make wallet and ethereum connect dialogs look more consistent

* add setup tests file for jest-dom

* remove chain id config and just use appChainId prop, add disconnect button to invalid chainId state

* switch handling of connect dialog state to the consuming app

* rename web3-provider package to just web3

* envs for each environment so we can specify chainId

* make web3container enforce connection before rendering childen

* add web3 provider using web3-react package

* make web3container enforce connection before rendering childen

* add container for getting network params

* Move ethereum config query to web3 container

* add basic deposit form elements

* add queries required for deposits, add asset default

* add bridge contract and deposit transaction

* break txhash

* restrict etherscan link props, use etherscan link in transaction dialogs

* use smart-contracts-sdk

* split hooks and components into different files, fix find deposit logic, add styles and progress for tx dialogs

* fix text colors for dark mode

* improve tx dialogs, rename deposit query

* position use buttons, fix select validation

* fix type errors after not being in strict mode, add allowance checking

* add deposit-limits component, fix types now that strict mode is enabled

* make contract hooks have a single instance

* split out dialogs into separate files, fix icon alignment

* improve error types for use transaction hook, add number save min and max for the amount input

* add validation for ethereum and vega addresses

* add unit test for deposit form component

* add icons and shared dialog styles so it better matches order transaction dialog

* fix underline class, reset finalized deposit

* fix type imports, use i18n function, regen types

* only pass contract address to token contract hook

* add vega env, refactor so retrieving asset contract address logic isn't duplicated

* add faucet functionality, combine dialogs into single transaction-dialog

* combine rendering logic into single func of transaction dialog, rever contract hooks to just useMemo

* use to field rather than connected key

* fix props and imports in deposit form test

* share faucetable condition, pass it to token contract

* pass contracts in as params to hooks to avoid multiple contract instances

* refetch balance in wallet after deposit, add comments

* use hook state for tracking deposit via partyid, add test for use ethereum transaction hook

* add deposits lib

* add last smart contract sdk package

* fix asset import in test

* tidy up ts-ignores

* pass arg for faucetable token contract

* add provider url to env vars and use in place of infura id, also update web3-connector to only allow the chain permitted by the app

* add type guard for erc20 assets

* fix intent shadow helper function, use arrow function for isEthereumError

* update etherscan link to use env vars for url base

* rename deposit related hooks to indicate read vs write calls

* move ethereum error class and helpers to react-helpers

* add use-ethereum-read-contract hook to contain fetch logic

* remove unused import

* move validation to lib, add hex check for vega public key

* use map for transaction modal states, pass confirmed prop to transaction dialog for deposits

* remove unused import for classnames
2022-04-06 10:34:51 -07:00

162 lines
4.0 KiB
TypeScript

import { gql } from '@apollo/client';
import type { NetworkParamsQuery } from './__generated__/NetworkParamsQuery';
import { Button, Splash } from '@vegaprotocol/ui-toolkit';
import { Web3Provider, Web3ConnectDialog } from '@vegaprotocol/web3';
import { useWeb3React } from '@web3-react/core';
import type { ReactNode } from 'react';
import { useEffect, useState } from 'react';
import { Connectors } from '../../lib/web3-connectors';
import { PageQueryContainer } from '../page-query-container';
import { t } from '@vegaprotocol/react-helpers';
export interface EthereumConfig {
network_id: string;
chain_id: string;
confirmations: number;
collateral_bridge_contract: {
address: string;
};
multisig_control_contract: {
address: string;
deployment_block_height: number;
};
staking_bridge_contract: {
address: string;
deployment_block_height: number;
};
token_vesting_contract: {
address: string;
deployment_block_height: number;
};
}
export const NETWORK_PARAMS_QUERY = gql`
query NetworkParamsQuery {
networkParameters {
key
value
}
}
`;
interface Web3ContainerProps {
children: (params: { ethereumConfig: EthereumConfig }) => ReactNode;
}
export const Web3Container = ({ children }: Web3ContainerProps) => {
const [dialogOpen, setDialogOpen] = useState(false);
return (
<PageQueryContainer<NetworkParamsQuery> query={NETWORK_PARAMS_QUERY}>
{(data) => {
const ethereumConfigParam = data.networkParameters?.find(
(np) => np.key === 'blockchains.ethereumConfig'
);
if (!ethereumConfigParam) {
return (
<Splash>
<p>{t('No ethereum config found')}</p>
</Splash>
);
}
let ethereumConfig: EthereumConfig;
try {
ethereumConfig = JSON.parse(ethereumConfigParam.value);
} catch {
return (
<Splash>
<p>{t('Could not parse config')}</p>
</Splash>
);
}
return (
<Web3Provider connectors={Connectors}>
<Web3Content
appChainId={Number(ethereumConfig.chain_id)}
setDialogOpen={setDialogOpen}
>
{children({ ethereumConfig })}
</Web3Content>
<Web3ConnectDialog
connectors={Connectors}
dialogOpen={dialogOpen}
setDialogOpen={setDialogOpen}
desiredChainId={Number(ethereumConfig.chain_id)}
/>
</Web3Provider>
);
}}
</PageQueryContainer>
);
};
interface Web3ContentProps {
children: ReactNode;
appChainId: number;
setDialogOpen: (isOpen: boolean) => void;
}
export const Web3Content = ({
children,
appChainId,
setDialogOpen,
}: Web3ContentProps) => {
const { isActive, error, connector, chainId } = useWeb3React();
useEffect(() => {
if (connector?.connectEagerly) {
connector.connectEagerly();
}
}, [connector]);
if (error) {
return (
<SplashWrapper>
<p className="mb-12">{t(`Something went wrong: ${error.message}`)}</p>
<Button onClick={() => connector.deactivate()}>
{t('Disconnect')}
</Button>
</SplashWrapper>
);
}
if (!isActive) {
return (
<SplashWrapper>
<p className="mb-12">{t('Connect your Ethereum wallet')}</p>
<Button onClick={() => setDialogOpen(true)}>{t('Connect')}</Button>
</SplashWrapper>
);
}
if (chainId !== appChainId) {
return (
<SplashWrapper>
<p className="mb-12">
{t(`This app only works on chain ID: ${appChainId}`)}
</p>
<Button onClick={() => connector.deactivate()}>
{t('Disconnect')}
</Button>
</SplashWrapper>
);
}
return <>{children}</>;
};
interface SplashWrapperProps {
children: ReactNode;
}
const SplashWrapper = ({ children }: SplashWrapperProps) => {
return (
<Splash>
<div className="text-center">{children}</div>
</Splash>
);
};