feat(trading): gas fee estimation for withdraw transaction (#5668)
This commit is contained in:
parent
a49139f127
commit
2002731c52
@ -7,6 +7,7 @@ import { AssetsDocument, type AssetsQuery } from './__generated__/Assets';
|
||||
import { AssetStatus } from '@vegaprotocol/types';
|
||||
import { type Asset } from './asset-data-provider';
|
||||
import { DENY_LIST } from './constants';
|
||||
import { type AssetFieldsFragment } from './__generated__/Asset';
|
||||
|
||||
export interface BuiltinAssetSource {
|
||||
__typename: 'BuiltinAsset';
|
||||
@ -89,3 +90,24 @@ export const useEnabledAssets = () => {
|
||||
variables: undefined,
|
||||
});
|
||||
};
|
||||
|
||||
/** Wrapped ETH symbol */
|
||||
const WETH = 'WETH';
|
||||
type WETHDetails = Pick<AssetFieldsFragment, 'symbol' | 'decimals' | 'quantum'>;
|
||||
/**
|
||||
* Tries to find WETH asset configuration on Vega in order to provide its
|
||||
* details, otherwise it returns hardcoded values.
|
||||
*/
|
||||
export const useWETH = (): WETHDetails => {
|
||||
const { data } = useAssetsDataProvider();
|
||||
if (data) {
|
||||
const weth = data.find((a) => a.symbol.toUpperCase() === WETH);
|
||||
if (weth) return weth;
|
||||
}
|
||||
|
||||
return {
|
||||
symbol: WETH,
|
||||
decimals: 18,
|
||||
quantum: '500000000000000', // 1 WETH ~= 2000 qUSD
|
||||
};
|
||||
};
|
||||
|
@ -47,5 +47,11 @@
|
||||
"Withdrawals of {{threshold}} {{symbol}} or more will be delayed for {{delay}}.": "Withdrawals of {{threshold}} {{symbol}} or more will be delayed for {{delay}}.",
|
||||
"Withdrawals ready": "Withdrawals ready",
|
||||
"You have no assets to withdraw": "You have no assets to withdraw",
|
||||
"Your funds have been unlocked for withdrawal - <0>View in block explorer<0>": "Your funds have been unlocked for withdrawal - <0>View in block explorer<0>"
|
||||
"Your funds have been unlocked for withdrawal - <0>View in block explorer<0>": "Your funds have been unlocked for withdrawal - <0>View in block explorer<0>",
|
||||
"Gas fee": "Gas fee",
|
||||
"Estimated gas fee for the withdrawal transaction (refreshes each 15 seconds)": "Estimated gas fee for the withdrawal transaction (refreshes each 15 seconds)",
|
||||
"It seems that the current gas prices are exceeding the amount you're trying to withdraw": "It seems that the current gas prices are exceeding the amount you're trying to withdraw",
|
||||
"The current gas price range": "The current gas price range",
|
||||
"min": "min",
|
||||
"max": "max"
|
||||
}
|
||||
|
42
libs/utils/src/lib/format/ether.spec.ts
Normal file
42
libs/utils/src/lib/format/ether.spec.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { EtherUnit, formatEther, unitiseEther } from './ether';
|
||||
|
||||
describe('unitiseEther', () => {
|
||||
it.each([
|
||||
[1, '1', EtherUnit.wei],
|
||||
[999, '999', EtherUnit.wei],
|
||||
[1000, '1', EtherUnit.kwei],
|
||||
[9999, '9.999', EtherUnit.kwei],
|
||||
[10000, '10', EtherUnit.kwei],
|
||||
[999999, '999.999', EtherUnit.kwei],
|
||||
[1000000, '1', EtherUnit.mwei],
|
||||
[999999999, '999.999999', EtherUnit.mwei],
|
||||
[1000000000, '1', EtherUnit.gwei],
|
||||
['999999999999999999', '999999999.999999999', EtherUnit.gwei], // max gwei
|
||||
[1e18, '1', EtherUnit.ether], // 1 ETH
|
||||
[1234e18, '1234', EtherUnit.ether], // 1234 ETH
|
||||
])('unitises %s to [%s, %s]', (value, expectedOutput, expectedUnit) => {
|
||||
const [output, unit] = unitiseEther(value);
|
||||
expect(output.toFixed()).toEqual(expectedOutput);
|
||||
expect(unit).toEqual(expectedUnit);
|
||||
});
|
||||
|
||||
it('unitises to requested unit', () => {
|
||||
const [output, unit] = unitiseEther(1, EtherUnit.kwei);
|
||||
expect(output).toEqual(BigNumber(0.001));
|
||||
expect(unit).toEqual(EtherUnit.kwei);
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatEther', () => {
|
||||
it.each([
|
||||
[1, EtherUnit.wei, '1 wei'],
|
||||
[12, EtherUnit.kwei, '12 kwei'],
|
||||
[123, EtherUnit.gwei, '123 gwei'],
|
||||
[3, EtherUnit.ether, '3 ETH'],
|
||||
[234.67776331, EtherUnit.gwei, '235 gwei'],
|
||||
[12.12, EtherUnit.gwei, '12 gwei'],
|
||||
])('formats [%s, %s] to "%s"', (value, unit, expectedOutput) => {
|
||||
expect(formatEther([BigNumber(value), unit])).toEqual(expectedOutput);
|
||||
});
|
||||
});
|
84
libs/utils/src/lib/format/ether.ts
Normal file
84
libs/utils/src/lib/format/ether.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { formatNumber, toBigNum } from './number';
|
||||
import type BigNumber from 'bignumber.js';
|
||||
|
||||
export enum EtherUnit {
|
||||
/** 1 wei = 10^-18 ETH */
|
||||
wei = '0',
|
||||
/** 1 kwei = 1000 wei */
|
||||
kwei = '3',
|
||||
/** 1 mwei = 1000 kwei */
|
||||
mwei = '6',
|
||||
/** 1 gwei = 1000 kwei */
|
||||
gwei = '9',
|
||||
|
||||
// other denominations:
|
||||
// microether = '12', // aka szabo, µETH
|
||||
// milliether = '15', // aka finney, mETH
|
||||
|
||||
/** 1 ETH = 1B gwei = 10^18 wei */
|
||||
ether = '18',
|
||||
}
|
||||
|
||||
export const etherUnitMapping: Record<EtherUnit, string> = {
|
||||
[EtherUnit.wei]: 'wei',
|
||||
[EtherUnit.kwei]: 'kwei',
|
||||
[EtherUnit.mwei]: 'mwei',
|
||||
[EtherUnit.gwei]: 'gwei',
|
||||
// [EtherUnit.microether]: 'µETH', // szabo
|
||||
// [EtherUnit.milliether]: 'mETH', // finney
|
||||
[EtherUnit.ether]: 'ETH',
|
||||
};
|
||||
|
||||
type InputValue = string | number | BigNumber;
|
||||
type UnitisedTuple = [value: BigNumber, unit: EtherUnit];
|
||||
|
||||
/**
|
||||
* Converts given raw value to the unitised tuple of amount and unit
|
||||
*/
|
||||
export const unitiseEther = (
|
||||
input: InputValue,
|
||||
forceUnit?: EtherUnit
|
||||
): UnitisedTuple => {
|
||||
const units = Object.values(EtherUnit).reverse();
|
||||
|
||||
let value = toBigNum(input, Number(forceUnit || EtherUnit.ether));
|
||||
let unit = forceUnit || EtherUnit.ether;
|
||||
|
||||
if (!forceUnit) {
|
||||
for (const u of units) {
|
||||
const v = toBigNum(input, Number(u));
|
||||
value = v;
|
||||
unit = u;
|
||||
if (v.isGreaterThanOrEqualTo(1)) break;
|
||||
}
|
||||
}
|
||||
|
||||
return [value, unit];
|
||||
};
|
||||
|
||||
/**
|
||||
* `formatNumber` wrapper for unitised ether values (attaches unit name)
|
||||
*/
|
||||
export const formatEther = (
|
||||
input: UnitisedTuple,
|
||||
decimals = 0,
|
||||
noUnit = false
|
||||
) => {
|
||||
const [value, unit] = input;
|
||||
const num = formatNumber(value, decimals);
|
||||
const unitName = noUnit ? '' : etherUnitMapping[unit];
|
||||
|
||||
return `${num} ${unitName}`.trim();
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility function that formats given raw amount as ETH.
|
||||
* Example:
|
||||
* Given value of `1` this will return `0.000000000000000001 ETH`
|
||||
*/
|
||||
export const asETH = (input: InputValue, noUnit = false) =>
|
||||
formatEther(
|
||||
unitiseEther(input, EtherUnit.ether),
|
||||
Number(EtherUnit.ether),
|
||||
noUnit
|
||||
);
|
@ -4,3 +4,4 @@ export * from './range';
|
||||
export * from './size';
|
||||
export * from './strings';
|
||||
export * from './trigger';
|
||||
export * from './ether';
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
toDecimal,
|
||||
toNumberParts,
|
||||
formatNumberRounded,
|
||||
toQUSD,
|
||||
} from './number';
|
||||
|
||||
describe('number utils', () => {
|
||||
@ -282,3 +283,22 @@ describe('formatNumberRounded', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toQUSD', () => {
|
||||
it.each([
|
||||
[0, 0, 0],
|
||||
[1, 1, 1],
|
||||
[1, 10, 0.1],
|
||||
[1, 100, 0.01],
|
||||
// real life examples
|
||||
[1000000, 1000000, 1], // USDC -> 1 USDC ~= 1 qUSD
|
||||
[500000, 1000000, 0.5], // USDC => 0.6 USDC ~= 0.5 qUSD
|
||||
[1e18, 1e18, 1], // VEGA -> 1 VEGA ~= 1 qUSD
|
||||
[123.45e18, 1e18, 123.45], // VEGA -> 1 VEGA ~= 1 qUSD
|
||||
[1e18, 5e14, 2000], // WETH -> 1 WETH ~= 2000 qUSD
|
||||
[1e9, 5e14, 0.000002], // gwei -> 1 gwei ~= 0.000002 qUSD
|
||||
[50000e9, 5e14, 0.1], // gwei -> 50000 gwei ~= 0.1 qUSD
|
||||
])('converts (%d, %d) to %d qUSD', (amount, quantum, expected) => {
|
||||
expect(toQUSD(amount, quantum).toNumber()).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
@ -26,7 +26,7 @@ export function toDecimal(numberOfDecimals: number) {
|
||||
}
|
||||
|
||||
export function toBigNum(
|
||||
rawValue: string | number,
|
||||
rawValue: string | number | BigNumber,
|
||||
decimals: number
|
||||
): BigNumber {
|
||||
const divides = new BigNumber(10).exponentiatedBy(decimals);
|
||||
@ -233,3 +233,24 @@ export const formatNumberRounded = (
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts given amount in one asset (determined by raw amount
|
||||
* and quantum values) to qUSD.
|
||||
* @param amount The raw amount
|
||||
* @param quantum The quantum value of the asset.
|
||||
*/
|
||||
export const toQUSD = (
|
||||
amount: string | number | BigNumber,
|
||||
quantum: string | number
|
||||
) => {
|
||||
const value = new BigNumber(amount);
|
||||
let q = new BigNumber(quantum);
|
||||
|
||||
if (q.isNaN() || q.isLessThanOrEqualTo(0)) {
|
||||
q = new BigNumber(1);
|
||||
}
|
||||
|
||||
const qUSD = value.dividedBy(q);
|
||||
return qUSD;
|
||||
};
|
||||
|
@ -19,6 +19,7 @@ export * from './lib/use-ethereum-transaction';
|
||||
export * from './lib/use-ethereum-withdraw-approval-toasts';
|
||||
export * from './lib/use-ethereum-withdraw-approvals-manager';
|
||||
export * from './lib/use-ethereum-withdraw-approvals-store';
|
||||
export * from './lib/use-gas-price';
|
||||
export * from './lib/use-get-withdraw-delay';
|
||||
export * from './lib/use-get-withdraw-threshold';
|
||||
export * from './lib/use-token-contract';
|
||||
|
111
libs/web3/src/lib/use-gas-price.ts
Normal file
111
libs/web3/src/lib/use-gas-price.ts
Normal file
@ -0,0 +1,111 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { useEthereumConfig } from './use-ethereum-config';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
const DEFAULT_INTERVAL = 15000; // 15 seconds
|
||||
|
||||
/**
|
||||
* These are the hex values of the collateral bridge contract methods.
|
||||
*
|
||||
* Collateral bridge address: 0x23872549cE10B40e31D6577e0A920088B0E0666a
|
||||
* Etherscan: https://etherscan.io/address/0x23872549cE10B40e31D6577e0A920088B0E0666a#writeContract
|
||||
*/
|
||||
export enum ContractMethod {
|
||||
DEPOSIT_ASSET = '0xf7683932',
|
||||
EXEMPT_DEPOSITOR = '0xb76fbb75',
|
||||
GLOBAL_RESUME = '0xd72ed529',
|
||||
GLOBAL_STOP = '0x9dfd3c88',
|
||||
LIST_ASSET = '0x0ff3562c',
|
||||
REMOVE_ASSET = '0xc76de358',
|
||||
REVOKE_EXEMPT_DEPOSITOR = '0x6a1c6fa4',
|
||||
SET_ASSET_LIMITS = '0x41fb776d',
|
||||
SET_WITHDRAW_DELAY = '0x5a246728',
|
||||
WITHDRAW_ASSET = '0x3ad90635',
|
||||
}
|
||||
|
||||
export type GasData = {
|
||||
/** The base (minimum) price of 1 unit of gas */
|
||||
basePrice: BigNumber;
|
||||
/** The maximum price of 1 unit of gas */
|
||||
maxPrice: BigNumber;
|
||||
/** The amount of gas (units) needed to process a transaction */
|
||||
gas: BigNumber;
|
||||
};
|
||||
|
||||
type Provider = NonNullable<ReturnType<typeof useWeb3React>['provider']>;
|
||||
|
||||
const retrieveGasData = async (
|
||||
provider: Provider,
|
||||
account: string,
|
||||
contractAddress: string,
|
||||
contractMethod: ContractMethod
|
||||
) => {
|
||||
try {
|
||||
const data = await provider.getFeeData();
|
||||
const estGasAmount = await provider.estimateGas({
|
||||
to: account,
|
||||
from: contractAddress,
|
||||
data: contractMethod,
|
||||
});
|
||||
|
||||
if (data.lastBaseFeePerGas && data.maxFeePerGas) {
|
||||
return {
|
||||
// converts also form ethers BigNumber to "normal" BigNumber
|
||||
basePrice: BigNumber(data.lastBaseFeePerGas.toString()),
|
||||
maxPrice: BigNumber(data.maxFeePerGas.toString()),
|
||||
gas: BigNumber(estGasAmount.toString()),
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
// NOOP - could not get the estimated gas or the fee data from
|
||||
// the network. This could happen if there's an issue with transaction
|
||||
// request parameters (e.g. to/from mismatch)
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the "current" gas price from the ethereum network.
|
||||
*/
|
||||
export const useGasPrice = (
|
||||
method: ContractMethod,
|
||||
interval = DEFAULT_INTERVAL
|
||||
): GasData | undefined => {
|
||||
const [gas, setGas] = useState<GasData | undefined>(undefined);
|
||||
const { provider, account } = useWeb3React();
|
||||
const { config } = useEthereumConfig();
|
||||
|
||||
useEffect(() => {
|
||||
if (!provider || !config || !account) return;
|
||||
|
||||
const retrieve = async () => {
|
||||
retrieveGasData(
|
||||
provider,
|
||||
account,
|
||||
config.collateral_bridge_contract.address,
|
||||
method
|
||||
).then((gasData) => {
|
||||
if (gasData) {
|
||||
setGas(gasData);
|
||||
}
|
||||
});
|
||||
};
|
||||
retrieve();
|
||||
|
||||
// Retrieves another estimation and prices in [interval] ms.
|
||||
let i: ReturnType<typeof setInterval>;
|
||||
if (interval > 0) {
|
||||
i = setInterval(() => {
|
||||
retrieve();
|
||||
}, interval);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (i) clearInterval(i);
|
||||
};
|
||||
}, [account, config, interval, method, provider]);
|
||||
|
||||
return gas;
|
||||
};
|
@ -27,6 +27,7 @@ import { useForm, Controller, useWatch } from 'react-hook-form';
|
||||
import { WithdrawLimits } from './withdraw-limits';
|
||||
import {
|
||||
ETHEREUM_EAGER_CONNECT,
|
||||
type GasData,
|
||||
useWeb3ConnectStore,
|
||||
useWeb3Disconnect,
|
||||
} from '@vegaprotocol/web3';
|
||||
@ -56,6 +57,7 @@ export interface WithdrawFormProps {
|
||||
delay: number | undefined;
|
||||
onSelectAsset: (assetId: string) => void;
|
||||
submitWithdraw: (withdrawal: WithdrawalArgs) => void;
|
||||
gasPrice?: GasData;
|
||||
}
|
||||
|
||||
const WithdrawDelayNotification = ({
|
||||
@ -117,6 +119,7 @@ export const WithdrawForm = ({
|
||||
delay,
|
||||
onSelectAsset,
|
||||
submitWithdraw,
|
||||
gasPrice,
|
||||
}: WithdrawFormProps) => {
|
||||
const t = useT();
|
||||
const ethereumAddress = useEthereumAddress();
|
||||
@ -247,6 +250,7 @@ export const WithdrawForm = ({
|
||||
delay={delay}
|
||||
balance={balance}
|
||||
asset={selectedAsset}
|
||||
gas={gasPrice}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { Asset } from '@vegaprotocol/assets';
|
||||
import { CompactNumber } from '@vegaprotocol/react-helpers';
|
||||
import { WITHDRAW_THRESHOLD_TOOLTIP_TEXT } from '@vegaprotocol/assets';
|
||||
import { WITHDRAW_THRESHOLD_TOOLTIP_TEXT, useWETH } from '@vegaprotocol/assets';
|
||||
import {
|
||||
KeyValueTable,
|
||||
KeyValueTableRow,
|
||||
@ -9,6 +9,16 @@ import {
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { useT } from './use-t';
|
||||
import { type GasData } from '@vegaprotocol/web3';
|
||||
import {
|
||||
asETH,
|
||||
formatEther,
|
||||
formatNumber,
|
||||
removeDecimal,
|
||||
toQUSD,
|
||||
unitiseEther,
|
||||
} from '@vegaprotocol/utils';
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface WithdrawLimitsProps {
|
||||
amount: string;
|
||||
@ -16,6 +26,7 @@ interface WithdrawLimitsProps {
|
||||
balance: BigNumber;
|
||||
delay: number | undefined;
|
||||
asset: Asset;
|
||||
gas?: GasData;
|
||||
}
|
||||
|
||||
export const WithdrawLimits = ({
|
||||
@ -24,6 +35,7 @@ export const WithdrawLimits = ({
|
||||
balance,
|
||||
delay,
|
||||
asset,
|
||||
gas,
|
||||
}: WithdrawLimitsProps) => {
|
||||
const t = useT();
|
||||
const delayTime =
|
||||
@ -64,6 +76,24 @@ export const WithdrawLimits = ({
|
||||
label: t('Delay time'),
|
||||
value: threshold && delay ? delayTime : '-',
|
||||
},
|
||||
{
|
||||
key: 'GAS_FEE',
|
||||
tooltip: t(
|
||||
'Estimated gas fee for the withdrawal transaction (refreshes each 15 seconds)'
|
||||
),
|
||||
label: t('Gas fee'),
|
||||
value: gas ? (
|
||||
<GasPrice
|
||||
gasPrice={gas}
|
||||
amount={{
|
||||
value: removeDecimal(amount, asset.decimals),
|
||||
quantum: asset.quantum,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
'-'
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
@ -91,3 +121,117 @@ export const WithdrawLimits = ({
|
||||
</KeyValueTable>
|
||||
);
|
||||
};
|
||||
|
||||
const GasPrice = ({
|
||||
gasPrice,
|
||||
amount,
|
||||
}: {
|
||||
gasPrice: WithdrawLimitsProps['gas'];
|
||||
amount: { value: string; quantum: string };
|
||||
}) => {
|
||||
const t = useT();
|
||||
const { quantum: wethQuantum } = useWETH();
|
||||
const { value, quantum } = amount;
|
||||
if (gasPrice) {
|
||||
const {
|
||||
basePrice: basePricePerGas,
|
||||
maxPrice: maxPricePerGas,
|
||||
gas,
|
||||
} = gasPrice;
|
||||
const basePrice = basePricePerGas.multipliedBy(gas);
|
||||
const maxPrice = maxPricePerGas.multipliedBy(gas);
|
||||
|
||||
const basePriceQUSD = toQUSD(basePrice, wethQuantum);
|
||||
const maxPriceQUSD = toQUSD(maxPrice, wethQuantum);
|
||||
|
||||
const withdrawalAmountQUSD = toQUSD(value, quantum);
|
||||
|
||||
const isExpensive =
|
||||
!withdrawalAmountQUSD.isLessThanOrEqualTo(0) &&
|
||||
withdrawalAmountQUSD.isLessThanOrEqualTo(maxPriceQUSD);
|
||||
const expensiveClassNames = {
|
||||
'text-vega-red-500':
|
||||
isExpensive && withdrawalAmountQUSD.isLessThanOrEqualTo(basePriceQUSD),
|
||||
'text-vega-orange-500':
|
||||
isExpensive &&
|
||||
withdrawalAmountQUSD.isGreaterThan(basePriceQUSD) &&
|
||||
withdrawalAmountQUSD.isLessThanOrEqualTo(maxPriceQUSD),
|
||||
};
|
||||
|
||||
const uBasePricePerGas = unitiseEther(basePricePerGas);
|
||||
const uMaxPricePerGas = unitiseEther(
|
||||
maxPricePerGas,
|
||||
uBasePricePerGas[1] // forces the same unit as min price
|
||||
);
|
||||
|
||||
const uBasePrice = unitiseEther(basePrice);
|
||||
const uMaxPrice = unitiseEther(maxPrice, uBasePrice[1]);
|
||||
|
||||
let range = (
|
||||
<span>
|
||||
{formatEther(uBasePrice, 0, true)} - {formatEther(uMaxPrice)}
|
||||
</span>
|
||||
);
|
||||
// displays range as ETH when it's greater that 1000000 gwei
|
||||
if (uBasePrice[0].isGreaterThan(1e6)) {
|
||||
range = (
|
||||
<span className="flex flex-col font-mono md:text-[11px]">
|
||||
<span>
|
||||
{t('min')}: {asETH(basePrice)}
|
||||
</span>
|
||||
<span>
|
||||
{t('max')}: {asETH(maxPrice)}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames('flex flex-col items-end self-end')}>
|
||||
<Tooltip description={t('The current gas price range')}>
|
||||
<span>
|
||||
{/* base price per gas unit */}
|
||||
{formatEther(uBasePricePerGas, 0, true)} -{' '}
|
||||
{formatEther(uMaxPricePerGas)} / gas
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
description={
|
||||
<div className="flex flex-col gap-1">
|
||||
{isExpensive && (
|
||||
<span className={classNames(expensiveClassNames)}>
|
||||
{t(
|
||||
"It seems that the current gas prices are exceeding the amount you're trying to withdraw"
|
||||
)}{' '}
|
||||
<strong>
|
||||
(~{formatNumber(withdrawalAmountQUSD, 2)} qUSD)
|
||||
</strong>
|
||||
.
|
||||
</span>
|
||||
)}
|
||||
<span>
|
||||
{formatNumber(gas)} gas × {asETH(basePricePerGas)} <br />{' '}
|
||||
= {asETH(basePrice)}
|
||||
</span>
|
||||
<span>
|
||||
{formatNumber(gas)} gas × {asETH(maxPricePerGas)} <br /> ={' '}
|
||||
{asETH(maxPrice)}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<span className={classNames(expensiveClassNames, 'text-xs')}>
|
||||
{range}
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
||||
<span className="text-muted text-xs">
|
||||
~{formatNumber(basePriceQUSD, 2)} - {formatNumber(maxPriceQUSD, 2)}{' '}
|
||||
qUSD
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return '-';
|
||||
};
|
||||
|
@ -38,6 +38,7 @@ jest.mock('@vegaprotocol/web3', () => ({
|
||||
useGetWithdrawDelay: () => {
|
||||
return () => Promise.resolve(10000);
|
||||
},
|
||||
useGasPrice: () => undefined,
|
||||
}));
|
||||
|
||||
describe('WithdrawManager', () => {
|
||||
|
@ -4,6 +4,7 @@ import { WithdrawForm } from './withdraw-form';
|
||||
import type { Asset } from '@vegaprotocol/assets';
|
||||
import type { AccountFieldsFragment } from '@vegaprotocol/accounts';
|
||||
import { useWithdrawAsset } from './use-withdraw-asset';
|
||||
import { ContractMethod, useGasPrice } from '@vegaprotocol/web3';
|
||||
|
||||
export interface WithdrawManagerProps {
|
||||
assets: Asset[];
|
||||
@ -20,6 +21,8 @@ export const WithdrawManager = ({
|
||||
}: WithdrawManagerProps) => {
|
||||
const { asset, balance, min, threshold, delay, handleSelectAsset } =
|
||||
useWithdrawAsset(assets, accounts, assetId);
|
||||
const gasPrice = useGasPrice(ContractMethod.WITHDRAW_ASSET);
|
||||
|
||||
return (
|
||||
<WithdrawForm
|
||||
selectedAsset={asset}
|
||||
@ -30,6 +33,7 @@ export const WithdrawManager = ({
|
||||
submitWithdraw={submit}
|
||||
threshold={threshold}
|
||||
delay={delay}
|
||||
gasPrice={gasPrice}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user