bridge_ui: ethereum gas estimates
Change-Id: I68db89ad9fafba700b6ad22f3870b9ac35233588
This commit is contained in:
parent
c67410cd15
commit
d0d5ea06cd
|
@ -1,7 +1,9 @@
|
||||||
import { makeStyles, MenuItem, TextField } from "@material-ui/core";
|
import { CHAIN_ID_ETH } from "@certusone/wormhole-sdk";
|
||||||
|
import { makeStyles, MenuItem, TextField, Typography } from "@material-ui/core";
|
||||||
import { Alert } from "@material-ui/lab";
|
import { Alert } from "@material-ui/lab";
|
||||||
import { useCallback, useMemo } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { EthGasEstimateSummary } from "../../hooks/useTransactionFees";
|
||||||
import { incrementStep, setTargetChain } from "../../store/attestSlice";
|
import { incrementStep, setTargetChain } from "../../store/attestSlice";
|
||||||
import {
|
import {
|
||||||
selectAttestIsTargetComplete,
|
selectAttestIsTargetComplete,
|
||||||
|
@ -58,8 +60,13 @@ function Target() {
|
||||||
</TextField>
|
</TextField>
|
||||||
<KeyAndBalance chainId={targetChain} />
|
<KeyAndBalance chainId={targetChain} />
|
||||||
<Alert severity="info" className={classes.alert}>
|
<Alert severity="info" className={classes.alert}>
|
||||||
You will have to pay transaction fees on{" "}
|
<Typography>
|
||||||
{CHAINS_BY_ID[targetChain].name} to attest this token.
|
You will have to pay transaction fees on{" "}
|
||||||
|
{CHAINS_BY_ID[targetChain].name} to attest this token.{" "}
|
||||||
|
</Typography>
|
||||||
|
{targetChain === CHAIN_ID_ETH && (
|
||||||
|
<EthGasEstimateSummary methodType="createWrapped" />
|
||||||
|
)}
|
||||||
</Alert>
|
</Alert>
|
||||||
<LowBalanceWarning chainId={targetChain} />
|
<LowBalanceWarning chainId={targetChain} />
|
||||||
<ButtonWithLoader
|
<ButtonWithLoader
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
|
import { CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
|
||||||
import { makeStyles, MenuItem, TextField } from "@material-ui/core";
|
import { makeStyles, MenuItem, TextField, Typography } from "@material-ui/core";
|
||||||
import { useCallback, useMemo } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import { ethers } from "ethers";
|
import { ethers } from "ethers";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
@ -24,6 +24,7 @@ import KeyAndBalance from "../KeyAndBalance";
|
||||||
import StepDescription from "../StepDescription";
|
import StepDescription from "../StepDescription";
|
||||||
import LowBalanceWarning from "../LowBalanceWarning";
|
import LowBalanceWarning from "../LowBalanceWarning";
|
||||||
import { Alert } from "@material-ui/lab";
|
import { Alert } from "@material-ui/lab";
|
||||||
|
import { EthGasEstimateSummary } from "../../hooks/useTransactionFees";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
transferField: {
|
transferField: {
|
||||||
|
@ -111,8 +112,13 @@ function Target() {
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
<Alert severity="info" className={classes.alert}>
|
<Alert severity="info" className={classes.alert}>
|
||||||
You will have to pay transaction fees on{" "}
|
<Typography>
|
||||||
{CHAINS_BY_ID[targetChain].name} to redeem your NFT.
|
You will have to pay transaction fees on{" "}
|
||||||
|
{CHAINS_BY_ID[targetChain].name} to redeem your NFT.
|
||||||
|
</Typography>
|
||||||
|
{targetChain === CHAIN_ID_ETH && (
|
||||||
|
<EthGasEstimateSummary methodType="nft" />
|
||||||
|
)}
|
||||||
</Alert>
|
</Alert>
|
||||||
<LowBalanceWarning chainId={targetChain} />
|
<LowBalanceWarning chainId={targetChain} />
|
||||||
<ButtonWithLoader
|
<ButtonWithLoader
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
|
import { CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
|
||||||
import { makeStyles, MenuItem, TextField } from "@material-ui/core";
|
import { makeStyles, MenuItem, TextField, Typography } from "@material-ui/core";
|
||||||
import { Alert } from "@material-ui/lab";
|
import { Alert } from "@material-ui/lab";
|
||||||
import { useCallback, useMemo } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import useIsWalletReady from "../../hooks/useIsWalletReady";
|
import useIsWalletReady from "../../hooks/useIsWalletReady";
|
||||||
import useSyncTargetAddress from "../../hooks/useSyncTargetAddress";
|
import useSyncTargetAddress from "../../hooks/useSyncTargetAddress";
|
||||||
|
import { EthGasEstimateSummary } from "../../hooks/useTransactionFees";
|
||||||
import {
|
import {
|
||||||
selectTransferIsTargetComplete,
|
selectTransferIsTargetComplete,
|
||||||
selectTransferShouldLockFields,
|
selectTransferShouldLockFields,
|
||||||
|
@ -112,8 +113,13 @@ function Target() {
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
<Alert severity="info" className={classes.alert}>
|
<Alert severity="info" className={classes.alert}>
|
||||||
You will have to pay transaction fees on{" "}
|
<Typography>
|
||||||
{CHAINS_BY_ID[targetChain].name} to redeem your tokens.
|
You will have to pay transaction fees on{" "}
|
||||||
|
{CHAINS_BY_ID[targetChain].name} to redeem your tokens.
|
||||||
|
</Typography>
|
||||||
|
{targetChain === CHAIN_ID_ETH && (
|
||||||
|
<EthGasEstimateSummary methodType="transfer" />
|
||||||
|
)}
|
||||||
</Alert>
|
</Alert>
|
||||||
<LowBalanceWarning chainId={targetChain} />
|
<LowBalanceWarning chainId={targetChain} />
|
||||||
<ButtonWithLoader
|
<ButtonWithLoader
|
||||||
|
|
|
@ -6,6 +6,8 @@ import {
|
||||||
} from "@certusone/wormhole-sdk";
|
} from "@certusone/wormhole-sdk";
|
||||||
import { Provider } from "@certusone/wormhole-sdk/node_modules/@ethersproject/abstract-provider";
|
import { Provider } from "@certusone/wormhole-sdk/node_modules/@ethersproject/abstract-provider";
|
||||||
import { formatUnits } from "@ethersproject/units";
|
import { formatUnits } from "@ethersproject/units";
|
||||||
|
import { Typography } from "@material-ui/core";
|
||||||
|
import { LocalGasStation } from "@material-ui/icons";
|
||||||
import { Connection, PublicKey } from "@solana/web3.js";
|
import { Connection, PublicKey } from "@solana/web3.js";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
|
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
|
||||||
|
@ -13,6 +15,14 @@ import { SOLANA_HOST } from "../utils/consts";
|
||||||
import { getMultipleAccountsRPC } from "../utils/solana";
|
import { getMultipleAccountsRPC } from "../utils/solana";
|
||||||
import useIsWalletReady from "./useIsWalletReady";
|
import useIsWalletReady from "./useIsWalletReady";
|
||||||
|
|
||||||
|
export type GasEstimate = {
|
||||||
|
currentGasPrice: string;
|
||||||
|
lowEstimate: string;
|
||||||
|
highEstimate: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MethodType = "nft" | "createWrapped" | "transfer";
|
||||||
|
|
||||||
//It's difficult to project how many fees the user will accrue during the
|
//It's difficult to project how many fees the user will accrue during the
|
||||||
//workflow, as a variable number of transactions can be sent, and different
|
//workflow, as a variable number of transactions can be sent, and different
|
||||||
//execution paths can be hit in the smart contracts, altering gas used.
|
//execution paths can be hit in the smart contracts, altering gas used.
|
||||||
|
@ -131,3 +141,109 @@ export default function useTransactionFees(chainId: ChainId) {
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useEthereumGasPrice(contract: MethodType) {
|
||||||
|
const { provider } = useEthereumProvider();
|
||||||
|
const { isReady } = useIsWalletReady(CHAIN_ID_ETH);
|
||||||
|
const [estimateResults, setEstimateResults] = useState<GasEstimate | null>(
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (provider && isReady && !estimateResults) {
|
||||||
|
getGasEstimates(provider, contract).then(
|
||||||
|
(results) => {
|
||||||
|
setEstimateResults(results);
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [provider, isReady, estimateResults, contract]);
|
||||||
|
|
||||||
|
const results = useMemo(() => estimateResults, [estimateResults]);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EthGasEstimateSummary({
|
||||||
|
methodType,
|
||||||
|
}: {
|
||||||
|
methodType: MethodType;
|
||||||
|
}) {
|
||||||
|
const estimate = useEthereumGasPrice(methodType);
|
||||||
|
if (!estimate) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Typography
|
||||||
|
component="div"
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
marginTop: 8,
|
||||||
|
flexWrap: "wrap",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<LocalGasStation fontSize="inherit" />
|
||||||
|
{estimate.currentGasPrice}
|
||||||
|
</div>
|
||||||
|
<div> </div>
|
||||||
|
<div>
|
||||||
|
Est. Fees: {estimate.lowEstimate} - {estimate.highEstimate} ETH
|
||||||
|
</div>
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const estimatesByContract = {
|
||||||
|
transfer: {
|
||||||
|
lowGasEstimate: BigInt(80000),
|
||||||
|
highGasEstimate: BigInt(130000),
|
||||||
|
},
|
||||||
|
nft: {
|
||||||
|
lowGasEstimate: BigInt(350000),
|
||||||
|
highGasEstimate: BigInt(500000),
|
||||||
|
},
|
||||||
|
createWrapped: {
|
||||||
|
lowGasEstimate: BigInt(450000),
|
||||||
|
highGasEstimate: BigInt(700000),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getGasEstimates(
|
||||||
|
provider: Provider,
|
||||||
|
contract: MethodType
|
||||||
|
): Promise<GasEstimate | null> {
|
||||||
|
const lowEstimateGasAmount = estimatesByContract[contract].lowGasEstimate;
|
||||||
|
const highEstimateGasAmount = estimatesByContract[contract].highGasEstimate;
|
||||||
|
|
||||||
|
let lowEstimate;
|
||||||
|
let highEstimate;
|
||||||
|
let currentGasPrice;
|
||||||
|
if (provider) {
|
||||||
|
const priceInWei = await provider.getGasPrice();
|
||||||
|
if (priceInWei) {
|
||||||
|
lowEstimate = parseFloat(
|
||||||
|
formatUnits(lowEstimateGasAmount * priceInWei.toBigInt(), "ether")
|
||||||
|
).toFixed(4);
|
||||||
|
highEstimate = parseFloat(
|
||||||
|
formatUnits(highEstimateGasAmount * priceInWei.toBigInt(), "ether")
|
||||||
|
).toFixed(4);
|
||||||
|
currentGasPrice = parseFloat(formatUnits(priceInWei, "gwei")).toFixed(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const output =
|
||||||
|
currentGasPrice && highEstimate && lowEstimate
|
||||||
|
? {
|
||||||
|
currentGasPrice,
|
||||||
|
lowEstimate,
|
||||||
|
highEstimate,
|
||||||
|
}
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
Loading…
Reference in New Issue