refacotr: deposit manager (#867)
* refactor: deposit manager with a zustand store and refetching balances after contracts complete * refactor: remove assetId query string functionality * chore: remove unused import * chore: add a comment with a link to code explanation * refactor: capture errors from deposit value get functions * refactor: add error handling for async perform funcs * feat: add assets to react helpers for types and erc20 check
This commit is contained in:
parent
3498b9d54b
commit
11be7aaa8a
@ -18,6 +18,7 @@ import type {
|
||||
} from './__generated__/Delegations';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useContracts } from '../../contexts/contracts/contracts-context';
|
||||
import { isAssetTypeERC20 } from '@vegaprotocol/react-helpers';
|
||||
|
||||
const DELEGATIONS_QUERY = gql`
|
||||
query Delegations($partyId: ID!) {
|
||||
@ -117,7 +118,7 @@ export const usePollForDelegations = () => {
|
||||
.filter((a) => a.type === AccountType.General)
|
||||
.map((a) => {
|
||||
const isVega =
|
||||
a.asset.source.__typename === 'ERC20' &&
|
||||
isAssetTypeERC20(a.asset) &&
|
||||
a.asset.source.contractAddress === vegaToken.address;
|
||||
|
||||
return {
|
||||
@ -131,8 +132,7 @@ export const usePollForDelegations = () => {
|
||||
),
|
||||
image: isVega ? vegaBlack : noIcon,
|
||||
border: isVega,
|
||||
address:
|
||||
a.asset.source.__typename === 'ERC20'
|
||||
address: isAssetTypeERC20(a.asset)
|
||||
? a.asset.source.contractAddress
|
||||
: undefined,
|
||||
};
|
||||
|
@ -16,14 +16,10 @@ const DEPOSIT_PAGE_QUERY = gql`
|
||||
}
|
||||
`;
|
||||
|
||||
interface DepositContainerProps {
|
||||
assetId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches data required for the Deposit page
|
||||
*/
|
||||
export const DepositContainer = ({ assetId }: DepositContainerProps) => {
|
||||
export const DepositContainer = () => {
|
||||
const { VEGA_ENV } = useEnvironment();
|
||||
|
||||
return (
|
||||
@ -41,7 +37,6 @@ export const DepositContainer = ({ assetId }: DepositContainerProps) => {
|
||||
return (
|
||||
<DepositManager
|
||||
assets={data.assets}
|
||||
initialAssetId={assetId}
|
||||
isFaucetable={VEGA_ENV !== 'MAINNET'}
|
||||
/>
|
||||
);
|
||||
|
@ -1,29 +1,12 @@
|
||||
import { useRouter } from 'next/router';
|
||||
import { useMemo } from 'react';
|
||||
import { Web3Container } from '../../../components/web3-container';
|
||||
import { DepositContainer } from './deposit-container';
|
||||
|
||||
const Deposit = () => {
|
||||
const { query } = useRouter();
|
||||
|
||||
// AssetId can be specified in the query string to allow link to deposit a particular asset
|
||||
const assetId = useMemo(() => {
|
||||
if (query.assetId && Array.isArray(query.assetId)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (Array.isArray(query.assetId)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return query.assetId;
|
||||
}, [query]);
|
||||
|
||||
return (
|
||||
<Web3Container>
|
||||
<div className="max-w-[420px] p-24 mx-auto">
|
||||
<h1 className="text-h3 mb-12">Deposit</h1>
|
||||
<DepositContainer assetId={assetId} />
|
||||
<DepositContainer />
|
||||
</div>
|
||||
</Web3Container>
|
||||
);
|
||||
|
@ -37,10 +37,8 @@ beforeEach(() => {
|
||||
submitApprove: jest.fn(),
|
||||
submitDeposit: jest.fn(),
|
||||
requestFaucet: jest.fn(),
|
||||
limits: {
|
||||
max: new BigNumber(20),
|
||||
deposited: new BigNumber(10),
|
||||
},
|
||||
allowance: new BigNumber(30),
|
||||
isFaucetable: true,
|
||||
};
|
||||
@ -134,7 +132,8 @@ describe('Deposit form', () => {
|
||||
<DepositForm
|
||||
{...props}
|
||||
balance={new BigNumber(100)}
|
||||
limits={{ max: new BigNumber(100), deposited: new BigNumber(10) }}
|
||||
max={new BigNumber(100)}
|
||||
deposited={new BigNumber(10)}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -213,18 +212,16 @@ describe('Deposit form', () => {
|
||||
const mockUseWeb3React = useWeb3React as jest.Mock;
|
||||
mockUseWeb3React.mockReturnValue({ account });
|
||||
|
||||
const limits = {
|
||||
max: new BigNumber(20),
|
||||
deposited: new BigNumber(10),
|
||||
};
|
||||
const balance = new BigNumber(50);
|
||||
|
||||
const max = new BigNumber(20);
|
||||
const deposited = new BigNumber(10);
|
||||
render(
|
||||
<DepositForm
|
||||
{...props}
|
||||
allowance={new BigNumber(100)}
|
||||
balance={balance}
|
||||
limits={limits}
|
||||
max={max}
|
||||
deposited={deposited}
|
||||
selectedAsset={asset}
|
||||
/>
|
||||
);
|
||||
@ -237,13 +234,13 @@ describe('Deposit form', () => {
|
||||
expect(
|
||||
screen.getByText('Maximum total deposit amount', { selector: 'th' })
|
||||
.nextElementSibling
|
||||
).toHaveTextContent(limits.max.toString());
|
||||
).toHaveTextContent(max.toString());
|
||||
expect(
|
||||
screen.getByText('Deposited', { selector: 'th' }).nextElementSibling
|
||||
).toHaveTextContent(limits.deposited.toString());
|
||||
).toHaveTextContent(deposited.toString());
|
||||
expect(
|
||||
screen.getByText('Remaining', { selector: 'th' }).nextElementSibling
|
||||
).toHaveTextContent(limits.max.minus(limits.deposited).toString());
|
||||
).toHaveTextContent(max.minus(deposited).toString());
|
||||
|
||||
fireEvent.change(screen.getByLabelText('Amount'), {
|
||||
target: { value: '8' },
|
||||
@ -257,7 +254,7 @@ describe('Deposit form', () => {
|
||||
expect(props.submitDeposit).toHaveBeenCalledWith({
|
||||
// @ts-ignore contract address definitely defined
|
||||
assetSource: asset.source.contractAddress,
|
||||
amount: '800',
|
||||
amount: '8',
|
||||
vegaPublicKey: vegaKey,
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
removeDecimal,
|
||||
ethereumAddress,
|
||||
t,
|
||||
required,
|
||||
@ -7,6 +7,7 @@ import {
|
||||
minSafe,
|
||||
maxSafe,
|
||||
addDecimal,
|
||||
isAssetTypeERC20,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
Button,
|
||||
@ -21,10 +22,9 @@ import { useWeb3React } from '@web3-react/core';
|
||||
import { Web3WalletInput } from '@vegaprotocol/web3';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useMemo, useEffect } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import { useMemo } from 'react';
|
||||
import { Controller, useForm, useWatch } from 'react-hook-form';
|
||||
import { DepositLimits } from './deposit-limits';
|
||||
import type { Asset } from './deposit-manager';
|
||||
|
||||
interface FormFields {
|
||||
asset: string;
|
||||
@ -45,10 +45,8 @@ export interface DepositFormProps {
|
||||
vegaPublicKey: string;
|
||||
}) => void;
|
||||
requestFaucet: () => void;
|
||||
limits: {
|
||||
max: BigNumber;
|
||||
deposited: BigNumber;
|
||||
} | null;
|
||||
max: BigNumber | undefined;
|
||||
deposited: BigNumber | undefined;
|
||||
allowance: BigNumber | undefined;
|
||||
isFaucetable?: boolean;
|
||||
}
|
||||
@ -58,10 +56,11 @@ export const DepositForm = ({
|
||||
selectedAsset,
|
||||
onSelectAsset,
|
||||
balance,
|
||||
max,
|
||||
deposited,
|
||||
submitApprove,
|
||||
submitDeposit,
|
||||
requestFaucet,
|
||||
limits,
|
||||
allowance,
|
||||
isFaucetable,
|
||||
}: DepositFormProps) => {
|
||||
@ -89,15 +88,14 @@ export const DepositForm = ({
|
||||
|
||||
submitDeposit({
|
||||
assetSource: selectedAsset.source.contractAddress,
|
||||
amount: removeDecimal(fields.amount, selectedAsset.decimals),
|
||||
amount: fields.amount,
|
||||
vegaPublicKey: fields.to,
|
||||
});
|
||||
};
|
||||
|
||||
const assetId = useWatch({ name: 'asset', control });
|
||||
const amount = useWatch({ name: 'amount', control });
|
||||
|
||||
const max = useMemo(() => {
|
||||
const maxAmount = useMemo(() => {
|
||||
const maxApproved = allowance ? allowance : new BigNumber(0);
|
||||
const maxAvailable = balance ? balance : new BigNumber(0);
|
||||
|
||||
@ -106,8 +104,8 @@ export const DepositForm = ({
|
||||
let maxLimit = new BigNumber(Infinity);
|
||||
|
||||
// A max limit of zero indicates that there is no limit
|
||||
if (limits && limits.max.isGreaterThan(0)) {
|
||||
maxLimit = limits.max.minus(limits.deposited);
|
||||
if (max && deposited && max.isGreaterThan(0)) {
|
||||
maxLimit = max.minus(deposited);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -116,7 +114,7 @@ export const DepositForm = ({
|
||||
limit: maxLimit,
|
||||
amount: BigNumber.minimum(maxLimit, maxApproved, maxAvailable),
|
||||
};
|
||||
}, [limits, allowance, balance]);
|
||||
}, [max, deposited, allowance, balance]);
|
||||
|
||||
const min = useMemo(() => {
|
||||
// Min viable amount given asset decimals EG for WEI 0.000000000000000001
|
||||
@ -127,10 +125,6 @@ export const DepositForm = ({
|
||||
return minViableAmount;
|
||||
}, [selectedAsset]);
|
||||
|
||||
useEffect(() => {
|
||||
onSelectAsset(assetId);
|
||||
}, [assetId, onSelectAsset]);
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit(onDeposit)}
|
||||
@ -154,16 +148,28 @@ export const DepositForm = ({
|
||||
)}
|
||||
</FormGroup>
|
||||
<FormGroup label={t('Asset')} labelFor="asset" className="relative">
|
||||
<Select {...register('asset', { validate: { required } })} id="asset">
|
||||
<Controller
|
||||
control={control}
|
||||
name="asset"
|
||||
rules={{ validate: { required } }}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
id="asset"
|
||||
{...field}
|
||||
onChange={(e) => {
|
||||
field.onChange(e);
|
||||
onSelectAsset(e.target.value);
|
||||
}}
|
||||
>
|
||||
<option value="">{t('Please select')}</option>
|
||||
{assets
|
||||
.filter((a) => a.source.__typename === 'ERC20')
|
||||
.map((a) => (
|
||||
{assets.filter(isAssetTypeERC20).map((a) => (
|
||||
<option key={a.id} value={a.id}>
|
||||
{a.name}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
{errors.asset?.message && (
|
||||
<InputError intent="danger" className="mt-4" forInput="asset">
|
||||
{errors.asset.message}
|
||||
@ -196,9 +202,9 @@ export const DepositForm = ({
|
||||
</UseButton>
|
||||
)}
|
||||
</FormGroup>
|
||||
{selectedAsset && limits && (
|
||||
{selectedAsset && max && deposited && (
|
||||
<div className="mb-20">
|
||||
<DepositLimits limits={limits} balance={balance} />
|
||||
<DepositLimits max={max} deposited={deposited} balance={balance} />
|
||||
</div>
|
||||
)}
|
||||
<FormGroup label={t('Amount')} labelFor="amount" className="relative">
|
||||
@ -212,14 +218,14 @@ export const DepositForm = ({
|
||||
minSafe: (value) => minSafe(new BigNumber(min))(value),
|
||||
maxSafe: (v) => {
|
||||
const value = new BigNumber(v);
|
||||
if (value.isGreaterThan(max.available)) {
|
||||
if (value.isGreaterThan(maxAmount.available)) {
|
||||
return t('Insufficient amount in Ethereum wallet');
|
||||
} else if (value.isGreaterThan(max.limit)) {
|
||||
} else if (value.isGreaterThan(maxAmount.limit)) {
|
||||
return t('Amount is above temporary deposit limit');
|
||||
} else if (value.isGreaterThan(max.approved)) {
|
||||
} else if (value.isGreaterThan(maxAmount.approved)) {
|
||||
return t('Amount is above approved amount');
|
||||
}
|
||||
return maxSafe(max.amount)(v);
|
||||
return maxSafe(maxAmount.amount)(v);
|
||||
},
|
||||
},
|
||||
})}
|
||||
|
@ -2,28 +2,30 @@ import { t } from '@vegaprotocol/react-helpers';
|
||||
import type BigNumber from 'bignumber.js';
|
||||
|
||||
interface DepositLimitsProps {
|
||||
limits: {
|
||||
max: BigNumber;
|
||||
deposited: BigNumber;
|
||||
};
|
||||
balance?: BigNumber;
|
||||
}
|
||||
|
||||
export const DepositLimits = ({ limits, balance }: DepositLimitsProps) => {
|
||||
export const DepositLimits = ({
|
||||
max,
|
||||
deposited,
|
||||
balance,
|
||||
}: DepositLimitsProps) => {
|
||||
let maxLimit = '';
|
||||
if (limits.max.isEqualTo(Infinity)) {
|
||||
if (max.isEqualTo(Infinity)) {
|
||||
maxLimit = t('No limit');
|
||||
} else if (limits.max.isGreaterThan(1_000_000)) {
|
||||
} else if (max.isGreaterThan(1_000_000)) {
|
||||
maxLimit = t('1m+');
|
||||
} else {
|
||||
maxLimit = limits.max.toString();
|
||||
maxLimit = max.toString();
|
||||
}
|
||||
|
||||
let remaining = '';
|
||||
if (limits.deposited.isEqualTo(0)) {
|
||||
if (deposited.isEqualTo(0)) {
|
||||
remaining = maxLimit;
|
||||
} else {
|
||||
const amountRemaining = limits.max.minus(limits.deposited);
|
||||
const amountRemaining = max.minus(deposited);
|
||||
remaining = amountRemaining.isGreaterThan(1_000_000)
|
||||
? t('1m+')
|
||||
: amountRemaining.toString();
|
||||
@ -44,7 +46,7 @@ export const DepositLimits = ({ limits, balance }: DepositLimitsProps) => {
|
||||
</tr>
|
||||
<tr>
|
||||
<th className="text-left font-normal">{t('Deposited')}</th>
|
||||
<td className="text-right">{limits.deposited.toString()}</td>
|
||||
<td className="text-right">{deposited.toString()}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th className="text-left font-normal">{t('Remaining')}</th>
|
||||
|
@ -1,121 +1,56 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { DepositForm } from './deposit-form';
|
||||
import { useGetBalanceOfERC20Token } from './use-get-balance-of-erc20-token';
|
||||
import { useSubmitDeposit } from './use-submit-deposit';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
import { useSubmitApproval } from './use-submit-approval';
|
||||
import { useGetDepositLimits } from './use-get-deposit-limits';
|
||||
import { useGetAllowance } from './use-get-allowance';
|
||||
import { useSubmitFaucet } from './use-submit-faucet';
|
||||
import { EthTxStatus, useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import { useTokenContract } from '@vegaprotocol/web3';
|
||||
import { removeDecimal } from '@vegaprotocol/react-helpers';
|
||||
|
||||
interface ERC20AssetSource {
|
||||
__typename: 'ERC20';
|
||||
contractAddress: string;
|
||||
}
|
||||
|
||||
interface BuiltinAssetSource {
|
||||
__typename: 'BuiltinAsset';
|
||||
}
|
||||
|
||||
type AssetSource = ERC20AssetSource | BuiltinAssetSource;
|
||||
export interface Asset {
|
||||
__typename: 'Asset';
|
||||
id: string;
|
||||
symbol: string;
|
||||
name: string;
|
||||
decimals: number;
|
||||
source: AssetSource;
|
||||
}
|
||||
import { useDepositStore } from './deposit-store';
|
||||
import { useCallback } from 'react';
|
||||
import { useDepositBalances } from './use-deposit-balances';
|
||||
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||
|
||||
interface DepositManagerProps {
|
||||
assets: Asset[];
|
||||
initialAssetId?: string;
|
||||
isFaucetable?: boolean;
|
||||
isFaucetable: boolean;
|
||||
}
|
||||
|
||||
export const DepositManager = ({
|
||||
assets,
|
||||
initialAssetId,
|
||||
isFaucetable,
|
||||
}: DepositManagerProps) => {
|
||||
const [assetId, setAssetId] = useState<string | undefined>(initialAssetId);
|
||||
|
||||
// Find the asset object from the select box
|
||||
const asset = useMemo(() => {
|
||||
const asset = assets?.find((a) => a.id === assetId);
|
||||
return asset;
|
||||
}, [assets, assetId]);
|
||||
|
||||
const { config } = useEthereumConfig();
|
||||
|
||||
const tokenContract = useTokenContract(
|
||||
asset?.source.__typename === 'ERC20'
|
||||
? asset.source.contractAddress
|
||||
: undefined,
|
||||
isFaucetable
|
||||
);
|
||||
|
||||
// Get users balance of the erc20 token selected
|
||||
const { balance, refetch: refetchBalance } = useGetBalanceOfERC20Token(
|
||||
tokenContract,
|
||||
asset?.decimals
|
||||
);
|
||||
|
||||
// Get temporary deposit limits
|
||||
const limits = useGetDepositLimits(asset);
|
||||
|
||||
// Get allowance (approved spending limit of brdige contract) for the selected asset
|
||||
const { allowance, refetch: refetchAllowance } = useGetAllowance(
|
||||
tokenContract,
|
||||
asset?.decimals
|
||||
);
|
||||
const { asset, balance, allowance, deposited, max, update } =
|
||||
useDepositStore();
|
||||
useDepositBalances(isFaucetable);
|
||||
|
||||
// Set up approve transaction
|
||||
const approve = useSubmitApproval(tokenContract);
|
||||
const approve = useSubmitApproval();
|
||||
|
||||
// Set up deposit transaction
|
||||
const deposit = useSubmitDeposit();
|
||||
|
||||
// Set up faucet transaction
|
||||
const faucet = useSubmitFaucet(tokenContract);
|
||||
const faucet = useSubmitFaucet();
|
||||
|
||||
// Update balance after confirmation event has been received
|
||||
useEffect(() => {
|
||||
if (
|
||||
faucet.transaction.status === EthTxStatus.Confirmed ||
|
||||
deposit.transaction.status === EthTxStatus.Confirmed
|
||||
) {
|
||||
refetchBalance();
|
||||
}
|
||||
}, [deposit.transaction.status, faucet.transaction.status, refetchBalance]);
|
||||
|
||||
// After an approval transaction refetch allowance
|
||||
useEffect(() => {
|
||||
if (approve.transaction.status === EthTxStatus.Confirmed) {
|
||||
refetchAllowance();
|
||||
}
|
||||
}, [approve.transaction.status, refetchAllowance]);
|
||||
const handleSelectAsset = useCallback(
|
||||
(id) => {
|
||||
const asset = assets.find((a) => a.id === id);
|
||||
if (!asset) return;
|
||||
update({ asset });
|
||||
},
|
||||
[assets, update]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<DepositForm
|
||||
balance={balance}
|
||||
selectedAsset={asset}
|
||||
onSelectAsset={(id) => setAssetId(id)}
|
||||
onSelectAsset={handleSelectAsset}
|
||||
assets={sortBy(assets, 'name')}
|
||||
submitApprove={() => {
|
||||
if (!asset || !config) return;
|
||||
const amount = removeDecimal('1000000', asset.decimals);
|
||||
approve.perform(config.collateral_bridge_contract.address, amount);
|
||||
}}
|
||||
submitDeposit={(args) => {
|
||||
deposit.perform(args.assetSource, args.amount, args.vegaPublicKey);
|
||||
}}
|
||||
submitApprove={() => approve.perform()}
|
||||
submitDeposit={(args) => deposit.perform(args)}
|
||||
requestFaucet={() => faucet.perform()}
|
||||
limits={limits}
|
||||
deposited={deposited}
|
||||
max={max}
|
||||
allowance={allowance}
|
||||
isFaucetable={isFaucetable}
|
||||
/>
|
||||
|
24
libs/deposits/src/lib/deposit-store.ts
Normal file
24
libs/deposits/src/lib/deposit-store.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import type { SetState } from 'zustand';
|
||||
import create from 'zustand';
|
||||
|
||||
interface DepositStore {
|
||||
balance: BigNumber;
|
||||
allowance: BigNumber;
|
||||
asset: Asset | undefined;
|
||||
deposited: BigNumber;
|
||||
max: BigNumber;
|
||||
update: (state: Partial<DepositStore>) => void;
|
||||
}
|
||||
|
||||
export const useDepositStore = create((set: SetState<DepositStore>) => ({
|
||||
balance: new BigNumber(0),
|
||||
allowance: new BigNumber(0),
|
||||
deposited: new BigNumber(0),
|
||||
max: new BigNumber(0),
|
||||
asset: undefined,
|
||||
update: (updatedState) => {
|
||||
set(updatedState);
|
||||
},
|
||||
}));
|
59
libs/deposits/src/lib/use-deposit-balances.ts
Normal file
59
libs/deposits/src/lib/use-deposit-balances.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { useBridgeContract, useTokenContract } from '@vegaprotocol/web3';
|
||||
import { useEffect } from 'react';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { useDepositStore } from './deposit-store';
|
||||
import { useGetAllowance } from './use-get-allowance';
|
||||
import { useGetBalanceOfERC20Token } from './use-get-balance-of-erc20-token';
|
||||
import { useGetDepositMaximum } from './use-get-deposit-maximum';
|
||||
import { useGetDepositedAmount } from './use-get-deposited-amount';
|
||||
import { isAssetTypeERC20 } from '@vegaprotocol/react-helpers';
|
||||
|
||||
/**
|
||||
* Hook which fetches all the balances required for despoiting
|
||||
* whenever the asset changes in the form
|
||||
*/
|
||||
export const useDepositBalances = (isFaucetable: boolean) => {
|
||||
const { asset, update } = useDepositStore();
|
||||
const tokenContract = useTokenContract(
|
||||
isAssetTypeERC20(asset) ? asset : undefined,
|
||||
isFaucetable
|
||||
);
|
||||
const bridgeContract = useBridgeContract(true);
|
||||
const getAllowance = useGetAllowance(tokenContract, asset);
|
||||
const getBalance = useGetBalanceOfERC20Token(tokenContract, asset);
|
||||
const getDepositMaximum = useGetDepositMaximum(bridgeContract, asset);
|
||||
const getDepositedAmount = useGetDepositedAmount(asset);
|
||||
|
||||
useEffect(() => {
|
||||
const getBalances = async () => {
|
||||
try {
|
||||
const [max, deposited, balance, allowance] = await Promise.all([
|
||||
getDepositMaximum(),
|
||||
getDepositedAmount(),
|
||||
getBalance(),
|
||||
getAllowance(),
|
||||
]);
|
||||
|
||||
update({
|
||||
max,
|
||||
deposited,
|
||||
balance,
|
||||
allowance,
|
||||
});
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
}
|
||||
};
|
||||
|
||||
if (asset) {
|
||||
getBalances();
|
||||
}
|
||||
}, [
|
||||
asset,
|
||||
update,
|
||||
getDepositMaximum,
|
||||
getDepositedAmount,
|
||||
getAllowance,
|
||||
getBalance,
|
||||
]);
|
||||
};
|
@ -1,30 +1,35 @@
|
||||
import type { Token } from '@vegaprotocol/smart-contracts';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { useCallback } from 'react';
|
||||
import { useEthereumConfig, useEthereumReadContract } from '@vegaprotocol/web3';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const useGetAllowance = (contract: Token | null, decimals?: number) => {
|
||||
export const useGetAllowance = (
|
||||
contract: Token | null,
|
||||
asset: Asset | undefined
|
||||
) => {
|
||||
const { account } = useWeb3React();
|
||||
const { config } = useEthereumConfig();
|
||||
|
||||
const getAllowance = useCallback(() => {
|
||||
if (!contract || !account || !config) {
|
||||
const getAllowance = useCallback(async () => {
|
||||
if (!contract || !account || !config || !asset) {
|
||||
return;
|
||||
}
|
||||
return contract.allowance(
|
||||
try {
|
||||
const res = await contract.allowance(
|
||||
account,
|
||||
config.collateral_bridge_contract.address
|
||||
);
|
||||
}, [contract, account, config]);
|
||||
|
||||
const { state, refetch } = useEthereumReadContract(getAllowance);
|
||||
return new BigNumber(addDecimal(res.toString(), asset.decimals));
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
return;
|
||||
}
|
||||
}, [contract, account, config, asset]);
|
||||
|
||||
const allowance =
|
||||
state.data && decimals
|
||||
? new BigNumber(addDecimal(state.data.toString(), decimals))
|
||||
: undefined;
|
||||
|
||||
return { allowance, refetch };
|
||||
return getAllowance;
|
||||
};
|
||||
|
@ -1,30 +1,29 @@
|
||||
import { useEthereumReadContract } from '@vegaprotocol/web3';
|
||||
import type { Token } from '@vegaprotocol/smart-contracts';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { useCallback } from 'react';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const useGetBalanceOfERC20Token = (
|
||||
contract: Token | null,
|
||||
decimals: number | undefined
|
||||
asset: Asset | undefined
|
||||
) => {
|
||||
const { account } = useWeb3React();
|
||||
|
||||
const getBalance = useCallback(() => {
|
||||
if (!contract || !account) {
|
||||
const getBalance = useCallback(async () => {
|
||||
if (!contract || !asset || !account) {
|
||||
return;
|
||||
}
|
||||
|
||||
return contract.balanceOf(account);
|
||||
}, [contract, account]);
|
||||
try {
|
||||
const res = await contract.balanceOf(account);
|
||||
return new BigNumber(addDecimal(res.toString(), asset.decimals));
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
return;
|
||||
}
|
||||
}, [contract, asset, account]);
|
||||
|
||||
const { state, refetch } = useEthereumReadContract(getBalance);
|
||||
|
||||
const balance =
|
||||
state.data && decimals
|
||||
? new BigNumber(addDecimal(state.data?.toString(), decimals))
|
||||
: undefined;
|
||||
|
||||
return { balance, refetch };
|
||||
return getBalance;
|
||||
};
|
||||
|
@ -1,69 +0,0 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { ethers } from 'ethers';
|
||||
import type { Asset } from './deposit-manager';
|
||||
import {
|
||||
useBridgeContract,
|
||||
useEthereumConfig,
|
||||
useEthereumReadContract,
|
||||
} from '@vegaprotocol/web3';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
|
||||
export const useGetDepositLimits = (asset?: Asset) => {
|
||||
const { account, provider } = useWeb3React();
|
||||
const { config } = useEthereumConfig();
|
||||
const contract = useBridgeContract(true);
|
||||
const [userTotal, setUserTotal] = useState<BigNumber | null>(null);
|
||||
const getLimits = useCallback(async () => {
|
||||
if (!contract || !asset || asset.source.__typename !== 'ERC20') {
|
||||
return;
|
||||
}
|
||||
|
||||
return contract.get_deposit_maximum(asset.source.contractAddress);
|
||||
}, [asset, contract]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
!provider ||
|
||||
!config ||
|
||||
!account ||
|
||||
!asset ||
|
||||
asset.source.__typename !== 'ERC20'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const abicoder = new ethers.utils.AbiCoder();
|
||||
const innerHash = ethers.utils.keccak256(
|
||||
abicoder.encode(['address', 'uint256'], [account, 4])
|
||||
);
|
||||
const storageLocation = ethers.utils.keccak256(
|
||||
abicoder.encode(
|
||||
['address', 'bytes32'],
|
||||
[asset.source.contractAddress, innerHash]
|
||||
)
|
||||
);
|
||||
(async () => {
|
||||
const res = await provider.getStorageAt(
|
||||
config.collateral_bridge_contract.address,
|
||||
storageLocation
|
||||
);
|
||||
const value = new BigNumber(res, 16).toString();
|
||||
setUserTotal(new BigNumber(addDecimal(value, asset.decimals)));
|
||||
})();
|
||||
}, [provider, config, account, asset]);
|
||||
|
||||
const {
|
||||
state: { data },
|
||||
} = useEthereumReadContract(getLimits);
|
||||
|
||||
if (!data || !userTotal || !asset) return null;
|
||||
|
||||
const max = new BigNumber(addDecimal(data.toString(), asset.decimals));
|
||||
|
||||
return {
|
||||
max: max.isEqualTo(0) ? new BigNumber(Infinity) : max,
|
||||
deposited: userTotal,
|
||||
};
|
||||
};
|
32
libs/deposits/src/lib/use-get-deposit-maximum.ts
Normal file
32
libs/deposits/src/lib/use-get-deposit-maximum.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { useCallback } from 'react';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
CollateralBridge,
|
||||
CollateralBridgeNew,
|
||||
} from '@vegaprotocol/smart-contracts';
|
||||
|
||||
export const useGetDepositMaximum = (
|
||||
contract: CollateralBridge | CollateralBridgeNew | null,
|
||||
asset: Asset | undefined
|
||||
) => {
|
||||
const getDepositMaximum = useCallback(async () => {
|
||||
if (!contract || !asset || asset.source.__typename !== 'ERC20') {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await contract.get_deposit_maximum(
|
||||
asset.source.contractAddress
|
||||
);
|
||||
const max = new BigNumber(addDecimal(res.toString(), asset.decimals));
|
||||
return max.isEqualTo(0) ? new BigNumber(Infinity) : max;
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
return;
|
||||
}
|
||||
}, [contract, asset]);
|
||||
|
||||
return getDepositMaximum;
|
||||
};
|
50
libs/deposits/src/lib/use-get-deposited-amount.ts
Normal file
50
libs/deposits/src/lib/use-get-deposited-amount.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { useCallback } from 'react';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { ethers } from 'ethers';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
|
||||
export const useGetDepositedAmount = (asset: Asset | undefined) => {
|
||||
const { account, provider } = useWeb3React();
|
||||
const { config } = useEthereumConfig();
|
||||
|
||||
// For an explaination of how this code works see here: https://gist.github.com/emilbayes/44a36f59b06b1f3edb9cf914041544ed
|
||||
const getDepositedAmount = useCallback(async () => {
|
||||
if (
|
||||
!provider ||
|
||||
!config ||
|
||||
!account ||
|
||||
!asset ||
|
||||
asset.source.__typename !== 'ERC20'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const abicoder = new ethers.utils.AbiCoder();
|
||||
const innerHash = ethers.utils.keccak256(
|
||||
abicoder.encode(['address', 'uint256'], [account, 4])
|
||||
);
|
||||
const storageLocation = ethers.utils.keccak256(
|
||||
abicoder.encode(
|
||||
['address', 'bytes32'],
|
||||
[asset.source.contractAddress, innerHash]
|
||||
)
|
||||
);
|
||||
const res = await provider.getStorageAt(
|
||||
config.collateral_bridge_contract.address,
|
||||
storageLocation
|
||||
);
|
||||
const value = new BigNumber(res, 16).toString();
|
||||
return new BigNumber(addDecimal(value, asset.decimals));
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
return;
|
||||
}
|
||||
}, [provider, asset, config, account]);
|
||||
|
||||
return getDepositedAmount;
|
||||
};
|
@ -1,10 +1,41 @@
|
||||
import { isAssetTypeERC20, removeDecimal } from '@vegaprotocol/react-helpers';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import type { Token } from '@vegaprotocol/smart-contracts';
|
||||
import { useEthereumTransaction } from '@vegaprotocol/web3';
|
||||
import {
|
||||
useEthereumConfig,
|
||||
useEthereumTransaction,
|
||||
useTokenContract,
|
||||
} from '@vegaprotocol/web3';
|
||||
import { useDepositStore } from './deposit-store';
|
||||
import { useGetAllowance } from './use-get-allowance';
|
||||
|
||||
export const useSubmitApproval = (contract: Token | null) => {
|
||||
export const useSubmitApproval = () => {
|
||||
const { config } = useEthereumConfig();
|
||||
const { asset, update } = useDepositStore();
|
||||
const contract = useTokenContract(
|
||||
isAssetTypeERC20(asset) ? asset : undefined,
|
||||
true
|
||||
);
|
||||
const getAllowance = useGetAllowance(contract, asset);
|
||||
const transaction = useEthereumTransaction<Token, 'approve'>(
|
||||
contract,
|
||||
'approve'
|
||||
);
|
||||
return transaction;
|
||||
return {
|
||||
...transaction,
|
||||
perform: async () => {
|
||||
if (!asset || !config) return;
|
||||
try {
|
||||
const amount = removeDecimal('1000000', asset.decimals);
|
||||
await transaction.perform(
|
||||
config.collateral_bridge_contract.address,
|
||||
amount
|
||||
);
|
||||
const allowance = await getAllowance();
|
||||
update({ allowance });
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -1,21 +1,29 @@
|
||||
import { gql, useSubscription } from '@apollo/client';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import type {
|
||||
DepositEvent,
|
||||
DepositEventVariables,
|
||||
} from './__generated__/DepositEvent';
|
||||
import { DepositStatus } from '@vegaprotocol/types';
|
||||
import { useState } from 'react';
|
||||
import { remove0x } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
isAssetTypeERC20,
|
||||
remove0x,
|
||||
removeDecimal,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
useBridgeContract,
|
||||
useEthereumConfig,
|
||||
useEthereumTransaction,
|
||||
useTokenContract,
|
||||
} from '@vegaprotocol/web3';
|
||||
import type {
|
||||
CollateralBridge,
|
||||
CollateralBridgeNew,
|
||||
} from '@vegaprotocol/smart-contracts';
|
||||
import { prepend0x } from '@vegaprotocol/smart-contracts';
|
||||
import { useDepositStore } from './deposit-store';
|
||||
import { useGetBalanceOfERC20Token } from './use-get-balance-of-erc20-token';
|
||||
|
||||
const DEPOSIT_EVENT_SUB = gql`
|
||||
subscription DepositEvent($partyId: ID!) {
|
||||
@ -32,17 +40,24 @@ const DEPOSIT_EVENT_SUB = gql`
|
||||
`;
|
||||
|
||||
export const useSubmitDeposit = () => {
|
||||
const { asset, update } = useDepositStore();
|
||||
const { config } = useEthereumConfig();
|
||||
const contract = useBridgeContract(true);
|
||||
const bridgeContract = useBridgeContract(true);
|
||||
const tokenContract = useTokenContract(
|
||||
isAssetTypeERC20(asset) ? asset : undefined,
|
||||
true
|
||||
);
|
||||
|
||||
// Store public key from contract arguments for use in the subscription,
|
||||
// NOTE: it may be different from the users connected key
|
||||
const [partyId, setPartyId] = useState<string | null>(null);
|
||||
|
||||
const getBalance = useGetBalanceOfERC20Token(tokenContract, asset);
|
||||
|
||||
const transaction = useEthereumTransaction<
|
||||
CollateralBridgeNew | CollateralBridge,
|
||||
'deposit_asset'
|
||||
>(contract, 'deposit_asset', config?.confirmations, true);
|
||||
>(bridgeContract, 'deposit_asset', config?.confirmations, true);
|
||||
|
||||
useSubscription<DepositEvent, DepositEventVariables>(DEPOSIT_EVENT_SUB, {
|
||||
variables: { partyId: partyId ? remove0x(partyId) : '' },
|
||||
@ -78,10 +93,22 @@ export const useSubmitDeposit = () => {
|
||||
|
||||
return {
|
||||
...transaction,
|
||||
perform: (...args: Parameters<typeof transaction.perform>) => {
|
||||
setPartyId(args[2]);
|
||||
const publicKey = prepend0x(args[2]);
|
||||
transaction.perform(args[0], args[1], publicKey);
|
||||
perform: async (args: {
|
||||
assetSource: string;
|
||||
amount: string;
|
||||
vegaPublicKey: string;
|
||||
}) => {
|
||||
if (!asset) return;
|
||||
try {
|
||||
setPartyId(args.vegaPublicKey);
|
||||
const publicKey = prepend0x(args.vegaPublicKey);
|
||||
const amount = removeDecimal(args.amount, asset.decimals);
|
||||
await transaction.perform(args.assetSource, amount, publicKey);
|
||||
const balance = await getBalance();
|
||||
update({ balance });
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -1,10 +1,31 @@
|
||||
import type { Token, TokenFaucetable } from '@vegaprotocol/smart-contracts';
|
||||
import { useEthereumTransaction } from '@vegaprotocol/web3';
|
||||
import type { TokenFaucetable } from '@vegaprotocol/smart-contracts';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { useEthereumTransaction, useTokenContract } from '@vegaprotocol/web3';
|
||||
import { useDepositStore } from './deposit-store';
|
||||
import { useGetBalanceOfERC20Token } from './use-get-balance-of-erc20-token';
|
||||
import { isAssetTypeERC20 } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const useSubmitFaucet = (contract: Token | TokenFaucetable | null) => {
|
||||
export const useSubmitFaucet = () => {
|
||||
const { asset, update } = useDepositStore();
|
||||
const contract = useTokenContract(
|
||||
isAssetTypeERC20(asset) ? asset : undefined,
|
||||
true
|
||||
);
|
||||
const getBalance = useGetBalanceOfERC20Token(contract, asset);
|
||||
const transaction = useEthereumTransaction<TokenFaucetable, 'faucet'>(
|
||||
contract,
|
||||
'faucet'
|
||||
);
|
||||
return transaction;
|
||||
return {
|
||||
...transaction,
|
||||
perform: async () => {
|
||||
try {
|
||||
await transaction.perform();
|
||||
const balance = await getBalance();
|
||||
update({ balance });
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
export * from './hooks';
|
||||
export * from './lib/assets';
|
||||
export * from './lib/context';
|
||||
export * from './lib/determine-id';
|
||||
export * from './lib/format';
|
||||
|
30
libs/react-helpers/src/lib/assets.ts
Normal file
30
libs/react-helpers/src/lib/assets.ts
Normal file
@ -0,0 +1,30 @@
|
||||
export interface ERC20AssetSource {
|
||||
__typename: 'ERC20';
|
||||
contractAddress: string;
|
||||
}
|
||||
|
||||
export interface BuiltinAssetSource {
|
||||
__typename: 'BuiltinAsset';
|
||||
}
|
||||
|
||||
export interface Asset {
|
||||
__typename: 'Asset';
|
||||
id: string;
|
||||
symbol: string;
|
||||
name: string;
|
||||
decimals: number;
|
||||
source: ERC20AssetSource | BuiltinAssetSource;
|
||||
}
|
||||
|
||||
export type ERC20Asset = Omit<Asset, 'source'> & {
|
||||
source: ERC20AssetSource;
|
||||
};
|
||||
|
||||
export type BuiltinAsset = Omit<Asset, 'source'> & {
|
||||
source: BuiltinAssetSource;
|
||||
};
|
||||
|
||||
export const isAssetTypeERC20 = (asset?: Asset): asset is ERC20Asset => {
|
||||
if (!asset?.source) return false;
|
||||
return asset.source.__typename === 'ERC20';
|
||||
};
|
@ -51,9 +51,11 @@ export const useEthereumReadContract = <T>(
|
||||
const response = await result;
|
||||
if (cancelRequest.current) return;
|
||||
dispatch({ type: ActionType.FETCHED, payload: response });
|
||||
return response;
|
||||
} catch (error) {
|
||||
if (cancelRequest.current) return;
|
||||
dispatch({ type: ActionType.ERROR, error: error as Error });
|
||||
return;
|
||||
}
|
||||
}, [contractFunc]);
|
||||
|
||||
|
@ -130,6 +130,7 @@ export const useEthereumTransaction = <
|
||||
error: new Error('Something went wrong'),
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
},
|
||||
[
|
||||
|
@ -1,26 +1,25 @@
|
||||
import type { ERC20Asset } from '@vegaprotocol/react-helpers';
|
||||
import { Token, TokenFaucetable } from '@vegaprotocol/smart-contracts';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useTokenContract = (
|
||||
contractAddress?: string,
|
||||
faucetable = false
|
||||
) => {
|
||||
export const useTokenContract = (asset?: ERC20Asset, faucetable = false) => {
|
||||
const { provider } = useWeb3React();
|
||||
|
||||
const contract = useMemo(() => {
|
||||
if (!provider || !contractAddress) {
|
||||
if (!provider || !asset) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const address = asset.source.contractAddress;
|
||||
|
||||
if (faucetable) {
|
||||
return new TokenFaucetable(contractAddress, signer || provider);
|
||||
return new TokenFaucetable(address, signer || provider);
|
||||
} else {
|
||||
return new Token(contractAddress, signer || provider);
|
||||
return new Token(address, signer || provider);
|
||||
}
|
||||
}, [provider, contractAddress, faucetable]);
|
||||
}, [provider, asset, faucetable]);
|
||||
|
||||
return contract;
|
||||
};
|
||||
|
@ -1,11 +1,13 @@
|
||||
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||
import { AccountType, WithdrawalStatus } from '@vegaprotocol/types';
|
||||
import merge from 'lodash/merge';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import type { Asset, Account } from './types';
|
||||
import type { Account } from './types';
|
||||
import type { Withdrawals_party_withdrawals } from './__generated__/Withdrawals';
|
||||
|
||||
export const generateAsset = (override?: PartialDeep<Asset>) => {
|
||||
const defaultAsset: Asset = {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-id',
|
||||
symbol: 'asset-symbol',
|
||||
name: 'asset-name',
|
||||
|
@ -1,24 +1,5 @@
|
||||
import type { AccountType } from '@vegaprotocol/types';
|
||||
|
||||
interface ERC20AssetSource {
|
||||
__typename: 'ERC20';
|
||||
contractAddress: string;
|
||||
}
|
||||
|
||||
interface BuiltinAssetSource {
|
||||
__typename: 'BuiltinAsset';
|
||||
}
|
||||
|
||||
type AssetSource = ERC20AssetSource | BuiltinAssetSource;
|
||||
|
||||
export interface Asset {
|
||||
id: string;
|
||||
symbol: string;
|
||||
name: string;
|
||||
decimals: number;
|
||||
source: AssetSource;
|
||||
}
|
||||
|
||||
export interface Account {
|
||||
type: AccountType;
|
||||
balance: string;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useCallback } from 'react';
|
||||
import type { Asset } from './types';
|
||||
import { useBridgeContract, useEthereumReadContract } from '@vegaprotocol/web3';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const useGetWithdrawLimits = (asset?: Asset) => {
|
||||
|
@ -3,8 +3,8 @@ import BigNumber from 'bignumber.js';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { WithdrawForm } from './withdraw-form';
|
||||
import { generateAsset } from './test-helpers';
|
||||
import type { Asset } from './types';
|
||||
import type { WithdrawFormProps } from './withdraw-form';
|
||||
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||
|
||||
jest.mock('@web3-react/core');
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
ethereumAddress,
|
||||
minSafe,
|
||||
@ -5,6 +6,7 @@ import {
|
||||
removeDecimal,
|
||||
required,
|
||||
maxSafe,
|
||||
isAssetTypeERC20,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
Button,
|
||||
@ -19,7 +21,6 @@ import BigNumber from 'bignumber.js';
|
||||
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import type { WithdrawalFields } from './use-withdraw';
|
||||
import type { Asset } from './types';
|
||||
import { WithdrawLimits } from './withdraw-limits';
|
||||
|
||||
interface FormFields {
|
||||
@ -99,9 +100,7 @@ export const WithdrawForm = ({
|
||||
id="asset"
|
||||
>
|
||||
<option value="">{t('Please select')}</option>
|
||||
{assets
|
||||
.filter((a) => a.source.__typename === 'ERC20')
|
||||
.map((a) => (
|
||||
{assets.filter(isAssetTypeERC20).map((a) => (
|
||||
<option key={a.id} value={a.id}>
|
||||
{a.name}
|
||||
</option>
|
||||
|
@ -5,10 +5,11 @@ import type { WithdrawalFields } from './use-withdraw';
|
||||
import { useWithdraw } from './use-withdraw';
|
||||
import { WithdrawDialog } from './withdraw-dialog';
|
||||
import { isExpectedEthereumError, EthTxStatus } from '@vegaprotocol/web3';
|
||||
import type { Asset } from '@vegaprotocol/react-helpers';
|
||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import type { Account, Asset } from './types';
|
||||
import type { Account } from './types';
|
||||
import { useGetWithdrawLimits } from './use-get-withdraw-limits';
|
||||
|
||||
export interface WithdrawManagerProps {
|
||||
|
Loading…
Reference in New Issue
Block a user