bridge_ui: Terra fee denomination support
This commit is contained in:
parent
8eea035490
commit
7882eccac4
|
@ -1,3 +1,4 @@
|
||||||
|
import { CHAIN_ID_TERRA } from "@certusone/wormhole-sdk";
|
||||||
import { CircularProgress, makeStyles } from "@material-ui/core";
|
import { CircularProgress, makeStyles } from "@material-ui/core";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import useFetchForeignAsset from "../../hooks/useFetchForeignAsset";
|
import useFetchForeignAsset from "../../hooks/useFetchForeignAsset";
|
||||||
|
@ -10,6 +11,7 @@ import {
|
||||||
} from "../../store/selectors";
|
} from "../../store/selectors";
|
||||||
import ButtonWithLoader from "../ButtonWithLoader";
|
import ButtonWithLoader from "../ButtonWithLoader";
|
||||||
import KeyAndBalance from "../KeyAndBalance";
|
import KeyAndBalance from "../KeyAndBalance";
|
||||||
|
import TerraFeeDenomPicker from "../TerraFeeDenomPicker";
|
||||||
import WaitingForWalletMessage from "./WaitingForWalletMessage";
|
import WaitingForWalletMessage from "./WaitingForWalletMessage";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
@ -45,7 +47,9 @@ function Create() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<KeyAndBalance chainId={targetChain} />
|
<KeyAndBalance chainId={targetChain} />
|
||||||
|
{targetChain === CHAIN_ID_TERRA && (
|
||||||
|
<TerraFeeDenomPicker disabled={disabled} />
|
||||||
|
)}
|
||||||
{foreignAssetInfo.isFetching ? (
|
{foreignAssetInfo.isFetching ? (
|
||||||
<>
|
<>
|
||||||
<div className={classes.spacer} />
|
<div className={classes.spacer} />
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
|
import { CHAIN_ID_SOLANA, CHAIN_ID_TERRA } from "@certusone/wormhole-sdk";
|
||||||
import { Alert } from "@material-ui/lab";
|
import { Alert } from "@material-ui/lab";
|
||||||
import { Link, makeStyles } from "@material-ui/core";
|
import { Link, makeStyles } from "@material-ui/core";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
@ -17,6 +17,7 @@ import KeyAndBalance from "../KeyAndBalance";
|
||||||
import TransactionProgress from "../TransactionProgress";
|
import TransactionProgress from "../TransactionProgress";
|
||||||
import WaitingForWalletMessage from "./WaitingForWalletMessage";
|
import WaitingForWalletMessage from "./WaitingForWalletMessage";
|
||||||
import { SOLANA_TOKEN_METADATA_PROGRAM_URL } from "../../utils/consts";
|
import { SOLANA_TOKEN_METADATA_PROGRAM_URL } from "../../utils/consts";
|
||||||
|
import TerraFeeDenomPicker from "../TerraFeeDenomPicker";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
alert: {
|
alert: {
|
||||||
|
@ -62,6 +63,9 @@ function Send() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<KeyAndBalance chainId={sourceChain} />
|
<KeyAndBalance chainId={sourceChain} />
|
||||||
|
{sourceChain === CHAIN_ID_TERRA && (
|
||||||
|
<TerraFeeDenomPicker disabled={disabled} />
|
||||||
|
)}
|
||||||
<ButtonWithLoader
|
<ButtonWithLoader
|
||||||
disabled={!isReady || disabled}
|
disabled={!isReady || disabled}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
|
@ -70,7 +74,7 @@ function Send() {
|
||||||
>
|
>
|
||||||
Attest
|
Attest
|
||||||
</ButtonWithLoader>
|
</ButtonWithLoader>
|
||||||
{sourceChain === CHAIN_ID_SOLANA ? <SolanaTokenMetadataWarning /> : null}
|
{sourceChain === CHAIN_ID_SOLANA && <SolanaTokenMetadataWarning />}
|
||||||
<WaitingForWalletMessage />
|
<WaitingForWalletMessage />
|
||||||
<TransactionProgress
|
<TransactionProgress
|
||||||
chainId={sourceChain}
|
chainId={sourceChain}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ChainId } from "@certusone/wormhole-sdk";
|
import { ChainId, CHAIN_ID_TERRA } from "@certusone/wormhole-sdk";
|
||||||
import { makeStyles, Typography } from "@material-ui/core";
|
import { makeStyles, Typography } from "@material-ui/core";
|
||||||
import { Alert } from "@material-ui/lab";
|
import { Alert } from "@material-ui/lab";
|
||||||
import useIsWalletReady from "../hooks/useIsWalletReady";
|
import useIsWalletReady from "../hooks/useIsWalletReady";
|
||||||
|
@ -18,18 +18,24 @@ function LowBalanceWarning({ chainId }: { chainId: ChainId }) {
|
||||||
const transactionFeeWarning = useTransactionFees(chainId);
|
const transactionFeeWarning = useTransactionFees(chainId);
|
||||||
const displayWarning =
|
const displayWarning =
|
||||||
isReady &&
|
isReady &&
|
||||||
transactionFeeWarning.balanceString &&
|
(chainId === CHAIN_ID_TERRA || transactionFeeWarning.balanceString) &&
|
||||||
transactionFeeWarning.isSufficientBalance === false;
|
transactionFeeWarning.isSufficientBalance === false;
|
||||||
const warningMessage = `This wallet has a very low ${getDefaultNativeCurrencySymbol(
|
|
||||||
chainId
|
const warningMessage =
|
||||||
)} balance and may not be able to pay for the upcoming transaction fees.`;
|
chainId === CHAIN_ID_TERRA
|
||||||
|
? "This wallet may not have sufficient funds to pay for the upcoming transaction fees."
|
||||||
|
: `This wallet has a very low ${getDefaultNativeCurrencySymbol(
|
||||||
|
chainId
|
||||||
|
)} balance and may not be able to pay for the upcoming transaction fees.`;
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<Alert severity="warning" variant="outlined" className={classes.alert}>
|
<Alert severity="warning" variant="outlined" className={classes.alert}>
|
||||||
<Typography variant="body1">{warningMessage}</Typography>
|
<Typography variant="body1">{warningMessage}</Typography>
|
||||||
<Typography variant="body1">
|
{chainId !== CHAIN_ID_TERRA ? (
|
||||||
{"Current balance: " + transactionFeeWarning.balanceString}
|
<Typography variant="body1">
|
||||||
</Typography>
|
{"Current balance: " + transactionFeeWarning.balanceString}
|
||||||
|
</Typography>
|
||||||
|
) : null}
|
||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { CHAIN_ID_TERRA } from "@certusone/wormhole-sdk";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { useHandleNFTRedeem } from "../../hooks/useHandleNFTRedeem";
|
import { useHandleNFTRedeem } from "../../hooks/useHandleNFTRedeem";
|
||||||
import useIsWalletReady from "../../hooks/useIsWalletReady";
|
import useIsWalletReady from "../../hooks/useIsWalletReady";
|
||||||
|
@ -5,6 +6,7 @@ import { selectNFTTargetChain } from "../../store/selectors";
|
||||||
import ButtonWithLoader from "../ButtonWithLoader";
|
import ButtonWithLoader from "../ButtonWithLoader";
|
||||||
import KeyAndBalance from "../KeyAndBalance";
|
import KeyAndBalance from "../KeyAndBalance";
|
||||||
import StepDescription from "../StepDescription";
|
import StepDescription from "../StepDescription";
|
||||||
|
import TerraFeeDenomPicker from "../TerraFeeDenomPicker";
|
||||||
import WaitingForWalletMessage from "./WaitingForWalletMessage";
|
import WaitingForWalletMessage from "./WaitingForWalletMessage";
|
||||||
|
|
||||||
function Redeem() {
|
function Redeem() {
|
||||||
|
@ -15,6 +17,9 @@ function Redeem() {
|
||||||
<>
|
<>
|
||||||
<StepDescription>Receive the NFT on the target chain</StepDescription>
|
<StepDescription>Receive the NFT on the target chain</StepDescription>
|
||||||
<KeyAndBalance chainId={targetChain} />
|
<KeyAndBalance chainId={targetChain} />
|
||||||
|
{targetChain === CHAIN_ID_TERRA && (
|
||||||
|
<TerraFeeDenomPicker disabled={disabled} />
|
||||||
|
)}
|
||||||
<ButtonWithLoader
|
<ButtonWithLoader
|
||||||
disabled={!isReady || disabled}
|
disabled={!isReady || disabled}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { CHAIN_ID_TERRA } from "@certusone/wormhole-sdk";
|
||||||
import { Alert } from "@material-ui/lab";
|
import { Alert } from "@material-ui/lab";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { useHandleNFTTransfer } from "../../hooks/useHandleNFTTransfer";
|
import { useHandleNFTTransfer } from "../../hooks/useHandleNFTTransfer";
|
||||||
|
@ -14,6 +15,7 @@ import ButtonWithLoader from "../ButtonWithLoader";
|
||||||
import KeyAndBalance from "../KeyAndBalance";
|
import KeyAndBalance from "../KeyAndBalance";
|
||||||
import ShowTx from "../ShowTx";
|
import ShowTx from "../ShowTx";
|
||||||
import StepDescription from "../StepDescription";
|
import StepDescription from "../StepDescription";
|
||||||
|
import TerraFeeDenomPicker from "../TerraFeeDenomPicker";
|
||||||
import TransactionProgress from "../TransactionProgress";
|
import TransactionProgress from "../TransactionProgress";
|
||||||
import WaitingForWalletMessage from "./WaitingForWalletMessage";
|
import WaitingForWalletMessage from "./WaitingForWalletMessage";
|
||||||
|
|
||||||
|
@ -41,6 +43,9 @@ function Send() {
|
||||||
Transfer the NFT to the Wormhole Token Bridge.
|
Transfer the NFT to the Wormhole Token Bridge.
|
||||||
</StepDescription>
|
</StepDescription>
|
||||||
<KeyAndBalance chainId={sourceChain} />
|
<KeyAndBalance chainId={sourceChain} />
|
||||||
|
{sourceChain === CHAIN_ID_TERRA && (
|
||||||
|
<TerraFeeDenomPicker disabled={disabled} />
|
||||||
|
)}
|
||||||
<Alert severity="info" variant="outlined">
|
<Alert severity="info" variant="outlined">
|
||||||
This will initiate the transfer on {CHAINS_BY_ID[sourceChain].name} and
|
This will initiate the transfer on {CHAINS_BY_ID[sourceChain].name} and
|
||||||
wait for finalization. If you navigate away from this page before
|
wait for finalization. If you navigate away from this page before
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
import {
|
||||||
|
MenuItem,
|
||||||
|
makeStyles,
|
||||||
|
TextField,
|
||||||
|
Typography,
|
||||||
|
ListItemIcon,
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import { useConnectedWallet } from "@terra-money/wallet-provider";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { setTerraFeeDenom } from "../store/feeSlice";
|
||||||
|
import { selectTerraFeeDenom } from "../store/selectors";
|
||||||
|
import useTerraNativeBalances from "../hooks/useTerraNativeBalances";
|
||||||
|
import { formatNativeDenom, getNativeTerraIcon } from "../utils/terra";
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
feePickerContainer: {
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
margin: `${theme.spacing(1)}px auto`,
|
||||||
|
maxWidth: 200,
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
"& .MuiSelect-root": {
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
listItemIcon: {
|
||||||
|
minWidth: 40,
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
height: 24,
|
||||||
|
maxWidth: 24,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
type TerraFeeDenomPickerProps = {
|
||||||
|
disabled: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function TerraFeeDenomPicker(props: TerraFeeDenomPickerProps) {
|
||||||
|
const terraFeeDenom = useSelector(selectTerraFeeDenom);
|
||||||
|
const wallet = useConnectedWallet();
|
||||||
|
const { balances } = useTerraNativeBalances(wallet?.walletAddress);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
const feeDenomItems = useMemo(() => {
|
||||||
|
const items = [];
|
||||||
|
if (balances) {
|
||||||
|
for (const [denom, amount] of Object.entries(balances)) {
|
||||||
|
if (amount === "0") continue;
|
||||||
|
const symbol = formatNativeDenom(denom);
|
||||||
|
if (symbol) {
|
||||||
|
items.push({
|
||||||
|
denom,
|
||||||
|
symbol,
|
||||||
|
icon: getNativeTerraIcon(symbol),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// prevent an out-of-range value from being selected
|
||||||
|
if (!items.find((item) => item.denom === terraFeeDenom)) {
|
||||||
|
const symbol = formatNativeDenom(terraFeeDenom);
|
||||||
|
items.push({
|
||||||
|
denom: terraFeeDenom,
|
||||||
|
symbol,
|
||||||
|
icon: getNativeTerraIcon(symbol),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}, [balances, terraFeeDenom]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.feePickerContainer}>
|
||||||
|
<Typography variant="caption">Fee Denomination</Typography>
|
||||||
|
<TextField
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
select
|
||||||
|
fullWidth
|
||||||
|
value={terraFeeDenom}
|
||||||
|
onChange={(event) => dispatch(setTerraFeeDenom(event.target.value))}
|
||||||
|
disabled={props.disabled}
|
||||||
|
className={classes.select}
|
||||||
|
>
|
||||||
|
{feeDenomItems.map((item) => {
|
||||||
|
return (
|
||||||
|
<MenuItem key={item.denom} value={item.denom}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<img
|
||||||
|
src={item.icon}
|
||||||
|
alt={item.symbol}
|
||||||
|
className={classes.icon}
|
||||||
|
/>
|
||||||
|
</ListItemIcon>
|
||||||
|
{item.symbol}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TextField>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import {
|
||||||
CHAIN_ID_OASIS,
|
CHAIN_ID_OASIS,
|
||||||
CHAIN_ID_POLYGON,
|
CHAIN_ID_POLYGON,
|
||||||
CHAIN_ID_SOLANA,
|
CHAIN_ID_SOLANA,
|
||||||
|
CHAIN_ID_TERRA,
|
||||||
isEVMChain,
|
isEVMChain,
|
||||||
WSOL_ADDRESS,
|
WSOL_ADDRESS,
|
||||||
} from "@certusone/wormhole-sdk";
|
} from "@certusone/wormhole-sdk";
|
||||||
|
@ -41,6 +42,7 @@ import KeyAndBalance from "../KeyAndBalance";
|
||||||
import SmartAddress from "../SmartAddress";
|
import SmartAddress from "../SmartAddress";
|
||||||
import { SolanaCreateAssociatedAddressAlternate } from "../SolanaCreateAssociatedAddress";
|
import { SolanaCreateAssociatedAddressAlternate } from "../SolanaCreateAssociatedAddress";
|
||||||
import StepDescription from "../StepDescription";
|
import StepDescription from "../StepDescription";
|
||||||
|
import TerraFeeDenomPicker from "../TerraFeeDenomPicker";
|
||||||
import AddToMetamask from "./AddToMetamask";
|
import AddToMetamask from "./AddToMetamask";
|
||||||
import WaitingForWalletMessage from "./WaitingForWalletMessage";
|
import WaitingForWalletMessage from "./WaitingForWalletMessage";
|
||||||
|
|
||||||
|
@ -112,6 +114,9 @@ function Redeem() {
|
||||||
<>
|
<>
|
||||||
<StepDescription>Receive the tokens on the target chain</StepDescription>
|
<StepDescription>Receive the tokens on the target chain</StepDescription>
|
||||||
<KeyAndBalance chainId={targetChain} />
|
<KeyAndBalance chainId={targetChain} />
|
||||||
|
{targetChain === CHAIN_ID_TERRA && (
|
||||||
|
<TerraFeeDenomPicker disabled={disabled} />
|
||||||
|
)}
|
||||||
{isNativeEligible && (
|
{isNativeEligible && (
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
control={
|
control={
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { isEVMChain } from "@certusone/wormhole-sdk";
|
import { CHAIN_ID_TERRA, isEVMChain } from "@certusone/wormhole-sdk";
|
||||||
import { Checkbox, FormControlLabel } from "@material-ui/core";
|
import { Checkbox, FormControlLabel } from "@material-ui/core";
|
||||||
import { Alert } from "@material-ui/lab";
|
import { Alert } from "@material-ui/lab";
|
||||||
import { ethers } from "ethers";
|
import { ethers } from "ethers";
|
||||||
|
@ -23,6 +23,7 @@ import ButtonWithLoader from "../ButtonWithLoader";
|
||||||
import KeyAndBalance from "../KeyAndBalance";
|
import KeyAndBalance from "../KeyAndBalance";
|
||||||
import ShowTx from "../ShowTx";
|
import ShowTx from "../ShowTx";
|
||||||
import StepDescription from "../StepDescription";
|
import StepDescription from "../StepDescription";
|
||||||
|
import TerraFeeDenomPicker from "../TerraFeeDenomPicker";
|
||||||
import TransactionProgress from "../TransactionProgress";
|
import TransactionProgress from "../TransactionProgress";
|
||||||
import SendConfirmationDialog from "./SendConfirmationDialog";
|
import SendConfirmationDialog from "./SendConfirmationDialog";
|
||||||
import WaitingForWalletMessage from "./WaitingForWalletMessage";
|
import WaitingForWalletMessage from "./WaitingForWalletMessage";
|
||||||
|
@ -130,6 +131,9 @@ function Send() {
|
||||||
Transfer the tokens to the Wormhole Token Bridge.
|
Transfer the tokens to the Wormhole Token Bridge.
|
||||||
</StepDescription>
|
</StepDescription>
|
||||||
<KeyAndBalance chainId={sourceChain} />
|
<KeyAndBalance chainId={sourceChain} />
|
||||||
|
{sourceChain === CHAIN_ID_TERRA && (
|
||||||
|
<TerraFeeDenomPicker disabled={disabled} />
|
||||||
|
)}
|
||||||
<Alert severity="info" variant="outlined">
|
<Alert severity="info" variant="outlined">
|
||||||
This will initiate the transfer on {CHAINS_BY_ID[sourceChain].name} and
|
This will initiate the transfer on {CHAINS_BY_ID[sourceChain].name} and
|
||||||
wait for finalization. If you navigate away from this page before
|
wait for finalization. If you navigate away from this page before
|
||||||
|
|
|
@ -22,6 +22,9 @@ import { postWithFees, waitForTerraExecution } from "../utils/terra";
|
||||||
import ButtonWithLoader from "./ButtonWithLoader";
|
import ButtonWithLoader from "./ButtonWithLoader";
|
||||||
import { useSnackbar } from "notistack";
|
import { useSnackbar } from "notistack";
|
||||||
import { Alert } from "@material-ui/lab";
|
import { Alert } from "@material-ui/lab";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
import { selectTerraFeeDenom } from "../store/selectors";
|
||||||
|
import TerraFeeDenomPicker from "./TerraFeeDenomPicker";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
formControl: {
|
formControl: {
|
||||||
|
@ -33,7 +36,11 @@ const useStyles = makeStyles((theme) => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const withdraw = async (wallet: ConnectedWallet, token: string) => {
|
const withdraw = async (
|
||||||
|
wallet: ConnectedWallet,
|
||||||
|
token: string,
|
||||||
|
feeDenom: string
|
||||||
|
) => {
|
||||||
const withdraw = new MsgExecuteContract(
|
const withdraw = new MsgExecuteContract(
|
||||||
wallet.walletAddress,
|
wallet.walletAddress,
|
||||||
TERRA_TOKEN_BRIDGE_ADDRESS,
|
TERRA_TOKEN_BRIDGE_ADDRESS,
|
||||||
|
@ -51,7 +58,8 @@ const withdraw = async (wallet: ConnectedWallet, token: string) => {
|
||||||
const txResult = await postWithFees(
|
const txResult = await postWithFees(
|
||||||
wallet,
|
wallet,
|
||||||
[withdraw],
|
[withdraw],
|
||||||
"Wormhole - Withdraw Tokens"
|
"Wormhole - Withdraw Tokens",
|
||||||
|
[feeDenom]
|
||||||
);
|
);
|
||||||
await waitForTerraExecution(txResult);
|
await waitForTerraExecution(txResult);
|
||||||
};
|
};
|
||||||
|
@ -62,13 +70,14 @@ export default function WithdrawTokensTerra() {
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const { enqueueSnackbar } = useSnackbar();
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
const feeDenom = useSelector(selectTerraFeeDenom);
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
if (wallet) {
|
if (wallet) {
|
||||||
(async () => {
|
(async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
await withdraw(wallet, token);
|
await withdraw(wallet, token, feeDenom);
|
||||||
enqueueSnackbar(null, {
|
enqueueSnackbar(null, {
|
||||||
content: <Alert severity="success">Transaction confirmed.</Alert>,
|
content: <Alert severity="success">Transaction confirmed.</Alert>,
|
||||||
});
|
});
|
||||||
|
@ -81,7 +90,7 @@ export default function WithdrawTokensTerra() {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
}, [wallet, token, enqueueSnackbar]);
|
}, [wallet, token, enqueueSnackbar, feeDenom]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="md">
|
<Container maxWidth="md">
|
||||||
|
@ -103,6 +112,7 @@ export default function WithdrawTokensTerra() {
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
|
<TerraFeeDenomPicker disabled={isLoading} />
|
||||||
<ButtonWithLoader
|
<ButtonWithLoader
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
disabled={!wallet || isLoading}
|
disabled={!wallet || isLoading}
|
||||||
|
|
|
@ -38,6 +38,7 @@ import {
|
||||||
selectAttestIsTargetComplete,
|
selectAttestIsTargetComplete,
|
||||||
selectAttestSourceAsset,
|
selectAttestSourceAsset,
|
||||||
selectAttestSourceChain,
|
selectAttestSourceChain,
|
||||||
|
selectTerraFeeDenom,
|
||||||
} from "../store/selectors";
|
} from "../store/selectors";
|
||||||
import {
|
import {
|
||||||
getBridgeAddressForChain,
|
getBridgeAddressForChain,
|
||||||
|
@ -156,7 +157,8 @@ async function terra(
|
||||||
dispatch: any,
|
dispatch: any,
|
||||||
enqueueSnackbar: any,
|
enqueueSnackbar: any,
|
||||||
wallet: ConnectedWallet,
|
wallet: ConnectedWallet,
|
||||||
asset: string
|
asset: string,
|
||||||
|
feeDenom: string
|
||||||
) {
|
) {
|
||||||
dispatch(setIsSending(true));
|
dispatch(setIsSending(true));
|
||||||
try {
|
try {
|
||||||
|
@ -165,7 +167,9 @@ async function terra(
|
||||||
wallet.terraAddress,
|
wallet.terraAddress,
|
||||||
asset
|
asset
|
||||||
);
|
);
|
||||||
const result = await postWithFees(wallet, [msg], "Create Wrapped");
|
const result = await postWithFees(wallet, [msg], "Create Wrapped", [
|
||||||
|
feeDenom,
|
||||||
|
]);
|
||||||
const info = await waitForTerraExecution(result);
|
const info = await waitForTerraExecution(result);
|
||||||
dispatch(setAttestTx({ id: info.txhash, block: info.height }));
|
dispatch(setAttestTx({ id: info.txhash, block: info.height }));
|
||||||
enqueueSnackbar(null, {
|
enqueueSnackbar(null, {
|
||||||
|
@ -211,6 +215,7 @@ export function useHandleAttest() {
|
||||||
const solanaWallet = useSolanaWallet();
|
const solanaWallet = useSolanaWallet();
|
||||||
const solPK = solanaWallet?.publicKey;
|
const solPK = solanaWallet?.publicKey;
|
||||||
const terraWallet = useConnectedWallet();
|
const terraWallet = useConnectedWallet();
|
||||||
|
const terraFeeDenom = useSelector(selectTerraFeeDenom);
|
||||||
const disabled = !isTargetComplete || isSending || isSendComplete;
|
const disabled = !isTargetComplete || isSending || isSendComplete;
|
||||||
const handleAttestClick = useCallback(() => {
|
const handleAttestClick = useCallback(() => {
|
||||||
if (isEVMChain(sourceChain) && !!signer) {
|
if (isEVMChain(sourceChain) && !!signer) {
|
||||||
|
@ -218,7 +223,7 @@ export function useHandleAttest() {
|
||||||
} else if (sourceChain === CHAIN_ID_SOLANA && !!solanaWallet && !!solPK) {
|
} else if (sourceChain === CHAIN_ID_SOLANA && !!solanaWallet && !!solPK) {
|
||||||
solana(dispatch, enqueueSnackbar, solPK, sourceAsset, solanaWallet);
|
solana(dispatch, enqueueSnackbar, solPK, sourceAsset, solanaWallet);
|
||||||
} else if (sourceChain === CHAIN_ID_TERRA && !!terraWallet) {
|
} else if (sourceChain === CHAIN_ID_TERRA && !!terraWallet) {
|
||||||
terra(dispatch, enqueueSnackbar, terraWallet, sourceAsset);
|
terra(dispatch, enqueueSnackbar, terraWallet, sourceAsset, terraFeeDenom);
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
@ -230,6 +235,7 @@ export function useHandleAttest() {
|
||||||
solPK,
|
solPK,
|
||||||
terraWallet,
|
terraWallet,
|
||||||
sourceAsset,
|
sourceAsset,
|
||||||
|
terraFeeDenom,
|
||||||
]);
|
]);
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
|
|
@ -28,6 +28,7 @@ import { setCreateTx, setIsCreating } from "../store/attestSlice";
|
||||||
import {
|
import {
|
||||||
selectAttestIsCreating,
|
selectAttestIsCreating,
|
||||||
selectAttestTargetChain,
|
selectAttestTargetChain,
|
||||||
|
selectTerraFeeDenom,
|
||||||
} from "../store/selectors";
|
} from "../store/selectors";
|
||||||
import {
|
import {
|
||||||
getTokenBridgeAddressForChain,
|
getTokenBridgeAddressForChain,
|
||||||
|
@ -133,7 +134,8 @@ async function terra(
|
||||||
enqueueSnackbar: any,
|
enqueueSnackbar: any,
|
||||||
wallet: ConnectedWallet,
|
wallet: ConnectedWallet,
|
||||||
signedVAA: Uint8Array,
|
signedVAA: Uint8Array,
|
||||||
shouldUpdate: boolean
|
shouldUpdate: boolean,
|
||||||
|
feeDenom: string
|
||||||
) {
|
) {
|
||||||
dispatch(setIsCreating(true));
|
dispatch(setIsCreating(true));
|
||||||
try {
|
try {
|
||||||
|
@ -151,7 +153,8 @@ async function terra(
|
||||||
const result = await postWithFees(
|
const result = await postWithFees(
|
||||||
wallet,
|
wallet,
|
||||||
[msg],
|
[msg],
|
||||||
"Wormhole - Create Wrapped"
|
"Wormhole - Create Wrapped",
|
||||||
|
[feeDenom]
|
||||||
);
|
);
|
||||||
dispatch(
|
dispatch(
|
||||||
setCreateTx({ id: result.result.txhash, block: result.result.height })
|
setCreateTx({ id: result.result.txhash, block: result.result.height })
|
||||||
|
@ -177,6 +180,7 @@ export function useHandleCreateWrapped(shouldUpdate: boolean) {
|
||||||
const isCreating = useSelector(selectAttestIsCreating);
|
const isCreating = useSelector(selectAttestIsCreating);
|
||||||
const { signer } = useEthereumProvider();
|
const { signer } = useEthereumProvider();
|
||||||
const terraWallet = useConnectedWallet();
|
const terraWallet = useConnectedWallet();
|
||||||
|
const terraFeeDenom = useSelector(selectTerraFeeDenom);
|
||||||
const handleCreateClick = useCallback(() => {
|
const handleCreateClick = useCallback(() => {
|
||||||
if (isEVMChain(targetChain) && !!signer && !!signedVAA) {
|
if (isEVMChain(targetChain) && !!signer && !!signedVAA) {
|
||||||
evm(
|
evm(
|
||||||
|
@ -202,7 +206,14 @@ export function useHandleCreateWrapped(shouldUpdate: boolean) {
|
||||||
shouldUpdate
|
shouldUpdate
|
||||||
);
|
);
|
||||||
} else if (targetChain === CHAIN_ID_TERRA && !!terraWallet && !!signedVAA) {
|
} else if (targetChain === CHAIN_ID_TERRA && !!terraWallet && !!signedVAA) {
|
||||||
terra(dispatch, enqueueSnackbar, terraWallet, signedVAA, shouldUpdate);
|
terra(
|
||||||
|
dispatch,
|
||||||
|
enqueueSnackbar,
|
||||||
|
terraWallet,
|
||||||
|
signedVAA,
|
||||||
|
shouldUpdate,
|
||||||
|
terraFeeDenom
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// enqueueSnackbar(
|
// enqueueSnackbar(
|
||||||
// "Creating wrapped tokens on this chain is not yet supported",
|
// "Creating wrapped tokens on this chain is not yet supported",
|
||||||
|
@ -221,6 +232,7 @@ export function useHandleCreateWrapped(shouldUpdate: boolean) {
|
||||||
signedVAA,
|
signedVAA,
|
||||||
signer,
|
signer,
|
||||||
shouldUpdate,
|
shouldUpdate,
|
||||||
|
terraFeeDenom,
|
||||||
]);
|
]);
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
|
|
@ -24,6 +24,7 @@ import { useEthereumProvider } from "../contexts/EthereumProviderContext";
|
||||||
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
||||||
import useTransferSignedVAA from "./useTransferSignedVAA";
|
import useTransferSignedVAA from "./useTransferSignedVAA";
|
||||||
import {
|
import {
|
||||||
|
selectTerraFeeDenom,
|
||||||
selectTransferIsRedeeming,
|
selectTransferIsRedeeming,
|
||||||
selectTransferTargetChain,
|
selectTransferTargetChain,
|
||||||
} from "../store/selectors";
|
} from "../store/selectors";
|
||||||
|
@ -132,7 +133,8 @@ async function terra(
|
||||||
dispatch: any,
|
dispatch: any,
|
||||||
enqueueSnackbar: any,
|
enqueueSnackbar: any,
|
||||||
wallet: ConnectedWallet,
|
wallet: ConnectedWallet,
|
||||||
signedVAA: Uint8Array
|
signedVAA: Uint8Array,
|
||||||
|
feeDenom: string
|
||||||
) {
|
) {
|
||||||
dispatch(setIsRedeeming(true));
|
dispatch(setIsRedeeming(true));
|
||||||
try {
|
try {
|
||||||
|
@ -144,7 +146,8 @@ async function terra(
|
||||||
const result = await postWithFees(
|
const result = await postWithFees(
|
||||||
wallet,
|
wallet,
|
||||||
[msg],
|
[msg],
|
||||||
"Wormhole - Complete Transfer"
|
"Wormhole - Complete Transfer",
|
||||||
|
[feeDenom]
|
||||||
);
|
);
|
||||||
dispatch(
|
dispatch(
|
||||||
setRedeemTx({ id: result.result.txhash, block: result.result.height })
|
setRedeemTx({ id: result.result.txhash, block: result.result.height })
|
||||||
|
@ -168,6 +171,7 @@ export function useHandleRedeem() {
|
||||||
const solPK = solanaWallet?.publicKey;
|
const solPK = solanaWallet?.publicKey;
|
||||||
const { signer } = useEthereumProvider();
|
const { signer } = useEthereumProvider();
|
||||||
const terraWallet = useConnectedWallet();
|
const terraWallet = useConnectedWallet();
|
||||||
|
const terraFeeDenom = useSelector(selectTerraFeeDenom);
|
||||||
const signedVAA = useTransferSignedVAA();
|
const signedVAA = useTransferSignedVAA();
|
||||||
const isRedeeming = useSelector(selectTransferIsRedeeming);
|
const isRedeeming = useSelector(selectTransferIsRedeeming);
|
||||||
const handleRedeemClick = useCallback(() => {
|
const handleRedeemClick = useCallback(() => {
|
||||||
|
@ -188,7 +192,7 @@ export function useHandleRedeem() {
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
} else if (targetChain === CHAIN_ID_TERRA && !!terraWallet && signedVAA) {
|
} else if (targetChain === CHAIN_ID_TERRA && !!terraWallet && signedVAA) {
|
||||||
terra(dispatch, enqueueSnackbar, terraWallet, signedVAA);
|
terra(dispatch, enqueueSnackbar, terraWallet, signedVAA, terraFeeDenom);
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
@ -200,6 +204,7 @@ export function useHandleRedeem() {
|
||||||
solanaWallet,
|
solanaWallet,
|
||||||
solPK,
|
solPK,
|
||||||
terraWallet,
|
terraWallet,
|
||||||
|
terraFeeDenom,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleRedeemNativeClick = useCallback(() => {
|
const handleRedeemNativeClick = useCallback(() => {
|
||||||
|
@ -220,7 +225,7 @@ export function useHandleRedeem() {
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
} else if (targetChain === CHAIN_ID_TERRA && !!terraWallet && signedVAA) {
|
} else if (targetChain === CHAIN_ID_TERRA && !!terraWallet && signedVAA) {
|
||||||
terra(dispatch, enqueueSnackbar, terraWallet, signedVAA); //TODO isNative = true
|
terra(dispatch, enqueueSnackbar, terraWallet, signedVAA, terraFeeDenom); //TODO isNative = true
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
@ -232,6 +237,7 @@ export function useHandleRedeem() {
|
||||||
solanaWallet,
|
solanaWallet,
|
||||||
solPK,
|
solPK,
|
||||||
terraWallet,
|
terraWallet,
|
||||||
|
terraFeeDenom,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
|
|
|
@ -32,6 +32,7 @@ import { useDispatch, useSelector } from "react-redux";
|
||||||
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
|
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
|
||||||
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
||||||
import {
|
import {
|
||||||
|
selectTerraFeeDenom,
|
||||||
selectTransferAmount,
|
selectTransferAmount,
|
||||||
selectTransferIsSendComplete,
|
selectTransferIsSendComplete,
|
||||||
selectTransferIsSending,
|
selectTransferIsSending,
|
||||||
|
@ -216,7 +217,8 @@ async function terra(
|
||||||
amount: string,
|
amount: string,
|
||||||
decimals: number,
|
decimals: number,
|
||||||
targetChain: ChainId,
|
targetChain: ChainId,
|
||||||
targetAddress: Uint8Array
|
targetAddress: Uint8Array,
|
||||||
|
feeDenom: string
|
||||||
) {
|
) {
|
||||||
dispatch(setIsSending(true));
|
dispatch(setIsSending(true));
|
||||||
try {
|
try {
|
||||||
|
@ -233,7 +235,8 @@ async function terra(
|
||||||
const result = await postWithFees(
|
const result = await postWithFees(
|
||||||
wallet,
|
wallet,
|
||||||
msgs,
|
msgs,
|
||||||
"Wormhole - Initiate Transfer"
|
"Wormhole - Initiate Transfer",
|
||||||
|
[feeDenom]
|
||||||
);
|
);
|
||||||
|
|
||||||
const info = await waitForTerraExecution(result);
|
const info = await waitForTerraExecution(result);
|
||||||
|
@ -286,6 +289,7 @@ export function useHandleTransfer() {
|
||||||
const solanaWallet = useSolanaWallet();
|
const solanaWallet = useSolanaWallet();
|
||||||
const solPK = solanaWallet?.publicKey;
|
const solPK = solanaWallet?.publicKey;
|
||||||
const terraWallet = useConnectedWallet();
|
const terraWallet = useConnectedWallet();
|
||||||
|
const terraFeeDenom = useSelector(selectTerraFeeDenom);
|
||||||
const sourceParsedTokenAccount = useSelector(
|
const sourceParsedTokenAccount = useSelector(
|
||||||
selectTransferSourceParsedTokenAccount
|
selectTransferSourceParsedTokenAccount
|
||||||
);
|
);
|
||||||
|
@ -353,7 +357,8 @@ export function useHandleTransfer() {
|
||||||
amount,
|
amount,
|
||||||
decimals,
|
decimals,
|
||||||
targetChain,
|
targetChain,
|
||||||
targetAddress
|
targetAddress,
|
||||||
|
terraFeeDenom
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
|
@ -374,6 +379,7 @@ export function useHandleTransfer() {
|
||||||
originAsset,
|
originAsset,
|
||||||
originChain,
|
originChain,
|
||||||
isNative,
|
isNative,
|
||||||
|
terraFeeDenom,
|
||||||
]);
|
]);
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
|
|
@ -37,9 +37,14 @@ export type MethodType = "nft" | "createWrapped" | "transfer";
|
||||||
//rather than a hardcoded value.
|
//rather than a hardcoded value.
|
||||||
const SOLANA_THRESHOLD_LAMPORTS: bigint = BigInt(300000);
|
const SOLANA_THRESHOLD_LAMPORTS: bigint = BigInt(300000);
|
||||||
const ETHEREUM_THRESHOLD_WEI: bigint = BigInt(35000000000000000);
|
const ETHEREUM_THRESHOLD_WEI: bigint = BigInt(35000000000000000);
|
||||||
const TERRA_THRESHOLD_ULUNA: bigint = BigInt(500000);
|
const TERRA_THRESHOLD_ULUNA: bigint = BigInt(100000);
|
||||||
|
const TERRA_THRESHOLD_UUSD: bigint = BigInt(10000000);
|
||||||
|
|
||||||
const isSufficientBalance = (chainId: ChainId, balance: bigint | undefined) => {
|
const isSufficientBalance = (
|
||||||
|
chainId: ChainId,
|
||||||
|
balance: bigint | undefined,
|
||||||
|
terraFeeDenom?: string
|
||||||
|
) => {
|
||||||
if (balance === undefined || !chainId) {
|
if (balance === undefined || !chainId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -49,13 +54,33 @@ const isSufficientBalance = (chainId: ChainId, balance: bigint | undefined) => {
|
||||||
if (isEVMChain(chainId)) {
|
if (isEVMChain(chainId)) {
|
||||||
return balance > ETHEREUM_THRESHOLD_WEI;
|
return balance > ETHEREUM_THRESHOLD_WEI;
|
||||||
}
|
}
|
||||||
if (CHAIN_ID_TERRA === chainId) {
|
if (terraFeeDenom === "uluna") {
|
||||||
return balance > TERRA_THRESHOLD_ULUNA;
|
return balance > TERRA_THRESHOLD_ULUNA;
|
||||||
}
|
}
|
||||||
|
if (terraFeeDenom === "uusd") {
|
||||||
|
return balance > TERRA_THRESHOLD_UUSD;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type TerraBalance = {
|
||||||
|
denom: string;
|
||||||
|
balance: bigint;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isSufficientBalanceTerra = (balances: TerraBalance[]) => {
|
||||||
|
return balances.some(({ denom, balance }) => {
|
||||||
|
if (denom === "uluna") {
|
||||||
|
return balance > TERRA_THRESHOLD_ULUNA;
|
||||||
|
}
|
||||||
|
if (denom === "uusd") {
|
||||||
|
return balance > TERRA_THRESHOLD_UUSD;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
//TODO move to more generic location
|
//TODO move to more generic location
|
||||||
const getBalanceSolana = async (walletAddress: string) => {
|
const getBalanceSolana = async (walletAddress: string) => {
|
||||||
const connection = new Connection(SOLANA_HOST);
|
const connection = new Connection(SOLANA_HOST);
|
||||||
|
@ -77,18 +102,25 @@ const getBalanceEvm = async (walletAddress: string, provider: Provider) => {
|
||||||
return provider.getBalance(walletAddress).then((result) => result.toBigInt());
|
return provider.getBalance(walletAddress).then((result) => result.toBigInt());
|
||||||
};
|
};
|
||||||
|
|
||||||
const getBalanceTerra = async (walletAddress: string) => {
|
const getBalancesTerra = async (walletAddress: string) => {
|
||||||
const TARGET_DENOM = "uluna";
|
const TARGET_DENOMS = ["uluna", "uusd"];
|
||||||
|
|
||||||
const lcd = new LCDClient(TERRA_HOST);
|
const lcd = new LCDClient(TERRA_HOST);
|
||||||
return lcd.bank
|
return lcd.bank
|
||||||
.balance(walletAddress)
|
.balance(walletAddress)
|
||||||
.then((coins) => {
|
.then((coins) => {
|
||||||
// coins doesn't support reduce
|
const balances = coins
|
||||||
const balancePairs = coins.map(({ amount, denom }) => [denom, amount]);
|
.filter(({ denom }) => {
|
||||||
const targetCoin = balancePairs.find((coin) => coin[0] === TARGET_DENOM);
|
return TARGET_DENOMS.includes(denom);
|
||||||
if (targetCoin) {
|
})
|
||||||
return BigInt(targetCoin[1].toString());
|
.map(({ amount, denom }) => {
|
||||||
|
return {
|
||||||
|
denom,
|
||||||
|
balance: BigInt(amount.toString()),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (balances) {
|
||||||
|
return balances;
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
|
@ -115,6 +147,7 @@ export default function useTransactionFees(chainId: ChainId) {
|
||||||
const { walletAddress, isReady } = useIsWalletReady(chainId);
|
const { walletAddress, isReady } = useIsWalletReady(chainId);
|
||||||
const { provider } = useEthereumProvider();
|
const { provider } = useEthereumProvider();
|
||||||
const [balance, setBalance] = useState<bigint | undefined>(undefined);
|
const [balance, setBalance] = useState<bigint | undefined>(undefined);
|
||||||
|
const [terraBalances, setTerraBalances] = useState<TerraBalance[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
|
@ -157,12 +190,17 @@ export default function useTransactionFees(chainId: ChainId) {
|
||||||
}
|
}
|
||||||
} else if (chainId === CHAIN_ID_TERRA && isReady && walletAddress) {
|
} else if (chainId === CHAIN_ID_TERRA && isReady && walletAddress) {
|
||||||
loadStart();
|
loadStart();
|
||||||
getBalanceTerra(walletAddress).then(
|
getBalancesTerra(walletAddress).then(
|
||||||
(result) => {
|
(results) => {
|
||||||
const adjustedresult =
|
const adjustedResults = results.map(({ denom, balance }) => {
|
||||||
result === undefined || result === null ? BigInt(0) : result;
|
return {
|
||||||
|
denom,
|
||||||
|
balance:
|
||||||
|
balance === undefined || balance === null ? BigInt(0) : balance,
|
||||||
|
};
|
||||||
|
});
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
setBalance(adjustedresult);
|
setTerraBalances(adjustedResults);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
@ -174,13 +212,16 @@ export default function useTransactionFees(chainId: ChainId) {
|
||||||
|
|
||||||
const results = useMemo(() => {
|
const results = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
isSufficientBalance: isSufficientBalance(chainId, balance),
|
isSufficientBalance:
|
||||||
|
chainId === CHAIN_ID_TERRA
|
||||||
|
? isSufficientBalanceTerra(terraBalances)
|
||||||
|
: isSufficientBalance(chainId, balance),
|
||||||
balance,
|
balance,
|
||||||
balanceString: toBalanceString(balance, chainId),
|
balanceString: toBalanceString(balance, chainId),
|
||||||
isLoading,
|
isLoading,
|
||||||
error,
|
error,
|
||||||
};
|
};
|
||||||
}, [balance, chainId, isLoading, error]);
|
}, [balance, terraBalances, chainId, isLoading, error]);
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||||
|
import { TERRA_DEFAULT_FEE_DENOM } from "../utils/consts";
|
||||||
|
|
||||||
|
export interface FeeSliceState {
|
||||||
|
terraFeeDenom: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: FeeSliceState = {
|
||||||
|
terraFeeDenom: TERRA_DEFAULT_FEE_DENOM,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const feeSlice = createSlice({
|
||||||
|
name: "fee",
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
setTerraFeeDenom: (state, action: PayloadAction<string>) => {
|
||||||
|
state.terraFeeDenom = action.payload;
|
||||||
|
},
|
||||||
|
reset: () => initialState,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { setTerraFeeDenom, reset } = feeSlice.actions;
|
||||||
|
|
||||||
|
export default feeSlice.reducer;
|
|
@ -3,6 +3,7 @@ import attestReducer from "./attestSlice";
|
||||||
import nftReducer from "./nftSlice";
|
import nftReducer from "./nftSlice";
|
||||||
import transferReducer from "./transferSlice";
|
import transferReducer from "./transferSlice";
|
||||||
import tokenReducer from "./tokenSlice";
|
import tokenReducer from "./tokenSlice";
|
||||||
|
import feeReducer from "./feeSlice";
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
|
@ -10,6 +11,7 @@ export const store = configureStore({
|
||||||
nft: nftReducer,
|
nft: nftReducer,
|
||||||
transfer: transferReducer,
|
transfer: transferReducer,
|
||||||
tokens: tokenReducer,
|
tokens: tokenReducer,
|
||||||
|
fee: feeReducer,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -307,3 +307,7 @@ export const selectTerraTokenMap = (state: RootState) => {
|
||||||
export const selectMarketsMap = (state: RootState) => {
|
export const selectMarketsMap = (state: RootState) => {
|
||||||
return state.tokens.marketsMap;
|
return state.tokens.marketsMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const selectTerraFeeDenom = (state: RootState) => {
|
||||||
|
return state.fee.terraFeeDenom;
|
||||||
|
};
|
||||||
|
|
|
@ -789,6 +789,7 @@ export const getMigrationAssetMap = (chainId: ChainId) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SUPPORTED_TERRA_TOKENS = ["uluna", "uusd"];
|
export const SUPPORTED_TERRA_TOKENS = ["uluna", "uusd"];
|
||||||
|
export const TERRA_DEFAULT_FEE_DENOM = SUPPORTED_TERRA_TOKENS[0];
|
||||||
|
|
||||||
export const TERRA_FCD_BASE =
|
export const TERRA_FCD_BASE =
|
||||||
CLUSTER === "mainnet"
|
CLUSTER === "mainnet"
|
||||||
|
|
|
@ -66,7 +66,8 @@ export const isValidTerraAddress = (address: string) => {
|
||||||
export async function postWithFees(
|
export async function postWithFees(
|
||||||
wallet: ConnectedWallet,
|
wallet: ConnectedWallet,
|
||||||
msgs: any[],
|
msgs: any[],
|
||||||
memo: string
|
memo: string,
|
||||||
|
feeDenoms: string[]
|
||||||
) {
|
) {
|
||||||
// don't try/catch, let errors propagate
|
// don't try/catch, let errors propagate
|
||||||
const lcd = new LCDClient(TERRA_HOST);
|
const lcd = new LCDClient(TERRA_HOST);
|
||||||
|
@ -81,7 +82,7 @@ export async function postWithFees(
|
||||||
[...msgs],
|
[...msgs],
|
||||||
{
|
{
|
||||||
memo,
|
memo,
|
||||||
feeDenoms: ["uluna"],
|
feeDenoms,
|
||||||
gasPrices,
|
gasPrices,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -89,7 +90,7 @@ export async function postWithFees(
|
||||||
const result = await wallet.post({
|
const result = await wallet.post({
|
||||||
msgs: [...msgs],
|
msgs: [...msgs],
|
||||||
memo,
|
memo,
|
||||||
feeDenoms: ["uluna"],
|
feeDenoms,
|
||||||
gasPrices,
|
gasPrices,
|
||||||
fee: feeEstimate,
|
fee: feeEstimate,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue