bridge_ui: success message
fixes https://github.com/certusone/wormhole/issues/374 Change-Id: Idb255da1e08fccfe3c79092ed552998178d71c02
This commit is contained in:
parent
0b517e9c76
commit
14e891ac6e
|
@ -35,9 +35,9 @@ export default function ButtonWithLoader({
|
||||||
error,
|
error,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
disabled: boolean;
|
disabled?: boolean;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
showLoader: boolean;
|
showLoader?: boolean;
|
||||||
error?: string;
|
error?: string;
|
||||||
children: ReactChild;
|
children: ReactChild;
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import {
|
||||||
|
ChainId,
|
||||||
|
CHAIN_ID_ETH,
|
||||||
|
CHAIN_ID_SOLANA,
|
||||||
|
} from "@certusone/wormhole-sdk";
|
||||||
|
import { Button, makeStyles, Typography } from "@material-ui/core";
|
||||||
|
import { Transaction } from "../store/transferSlice";
|
||||||
|
import { CLUSTER } from "../utils/consts";
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
tx: {
|
||||||
|
marginTop: theme.spacing(1),
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
viewButton: {
|
||||||
|
marginTop: theme.spacing(1),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function ShowTx({
|
||||||
|
chainId,
|
||||||
|
tx,
|
||||||
|
}: {
|
||||||
|
chainId: ChainId;
|
||||||
|
tx: Transaction;
|
||||||
|
}) {
|
||||||
|
const classes = useStyles();
|
||||||
|
const showExplorerLink = CLUSTER === "testnet" || CLUSTER === "mainnet";
|
||||||
|
const explorerAddress =
|
||||||
|
chainId === CHAIN_ID_ETH
|
||||||
|
? `https://${CLUSTER === "testnet" ? "goerli." : ""}etherscan.io/tx/${
|
||||||
|
tx?.id
|
||||||
|
}`
|
||||||
|
: chainId === CHAIN_ID_SOLANA
|
||||||
|
? `https://explorer.solana.com/tx/${tx?.id}${
|
||||||
|
CLUSTER === "testnet" ? "?cluster=testnet" : ""
|
||||||
|
}`
|
||||||
|
: undefined;
|
||||||
|
const explorerName = chainId === CHAIN_ID_ETH ? "Etherscan" : "Explorer";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.tx}>
|
||||||
|
<Typography component="div" variant="body2">
|
||||||
|
{tx.id}
|
||||||
|
</Typography>
|
||||||
|
{showExplorerLink && explorerAddress ? (
|
||||||
|
<Button
|
||||||
|
href={explorerAddress}
|
||||||
|
target="_blank"
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
className={classes.viewButton}
|
||||||
|
>
|
||||||
|
View on {explorerName}
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,4 +1,13 @@
|
||||||
import { makeStyles, Typography } from "@material-ui/core";
|
import { makeStyles, Typography } from "@material-ui/core";
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import {
|
||||||
|
selectTransferRedeemTx,
|
||||||
|
selectTransferTargetChain,
|
||||||
|
} from "../../store/selectors";
|
||||||
|
import { reset } from "../../store/transferSlice";
|
||||||
|
import ButtonWithLoader from "../ButtonWithLoader";
|
||||||
|
import ShowTx from "../ShowTx";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
description: {
|
description: {
|
||||||
|
@ -8,17 +17,29 @@ const useStyles = makeStyles((theme) => ({
|
||||||
|
|
||||||
export default function RedeemPreview() {
|
export default function RedeemPreview() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const targetChain = useSelector(selectTransferTargetChain);
|
||||||
|
const redeemTx = useSelector(selectTransferRedeemTx);
|
||||||
|
const handleResetClick = useCallback(() => {
|
||||||
|
dispatch(reset());
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
const explainerString =
|
const explainerString =
|
||||||
"Success! The redeem transaction was submitted. The tokens will become available once the transaction confirms.";
|
"Success! The redeem transaction was submitted. The tokens will become available once the transaction confirms.";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Typography
|
<>
|
||||||
component="div"
|
<Typography
|
||||||
variant="subtitle2"
|
component="div"
|
||||||
className={classes.description}
|
variant="subtitle2"
|
||||||
>
|
className={classes.description}
|
||||||
{explainerString}
|
>
|
||||||
</Typography>
|
{explainerString}
|
||||||
|
</Typography>
|
||||||
|
{redeemTx ? <ShowTx chainId={targetChain} tx={redeemTx} /> : null}
|
||||||
|
<ButtonWithLoader onClick={handleResetClick}>
|
||||||
|
Transfer More Tokens!
|
||||||
|
</ButtonWithLoader>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,41 @@
|
||||||
import { makeStyles, Typography } from "@material-ui/core";
|
import { makeStyles, Typography } from "@material-ui/core";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
import {
|
||||||
|
selectTransferSourceChain,
|
||||||
|
selectTransferTransferTx,
|
||||||
|
} from "../../store/selectors";
|
||||||
|
import ShowTx from "../ShowTx";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
description: {
|
description: {
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
},
|
},
|
||||||
|
tx: {
|
||||||
|
marginTop: theme.spacing(1),
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
viewButton: {
|
||||||
|
marginTop: theme.spacing(1),
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default function SendPreview() {
|
export default function SendPreview() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
const sourceChain = useSelector(selectTransferSourceChain);
|
||||||
|
const transferTx = useSelector(selectTransferTransferTx);
|
||||||
|
|
||||||
const explainerString = "The tokens have been sent!";
|
const explainerString = "The tokens have been sent!";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Typography
|
<>
|
||||||
component="div"
|
<Typography
|
||||||
variant="subtitle2"
|
component="div"
|
||||||
className={classes.description}
|
variant="subtitle2"
|
||||||
>
|
className={classes.description}
|
||||||
{explainerString}
|
>
|
||||||
</Typography>
|
{explainerString}
|
||||||
|
</Typography>
|
||||||
|
{transferTx ? <ShowTx chainId={sourceChain} tx={transferTx} /> : null}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import useFetchTargetAsset from "../../hooks/useFetchTargetAsset";
|
||||||
import useGetBalanceEffect from "../../hooks/useGetBalanceEffect";
|
import useGetBalanceEffect from "../../hooks/useGetBalanceEffect";
|
||||||
import {
|
import {
|
||||||
selectTransferActiveStep,
|
selectTransferActiveStep,
|
||||||
|
selectTransferIsRedeemComplete,
|
||||||
selectTransferIsRedeeming,
|
selectTransferIsRedeeming,
|
||||||
selectTransferIsSendComplete,
|
selectTransferIsSendComplete,
|
||||||
selectTransferIsSending,
|
selectTransferIsSending,
|
||||||
|
@ -20,13 +21,13 @@ import {
|
||||||
import { setStep } from "../../store/transferSlice";
|
import { setStep } from "../../store/transferSlice";
|
||||||
import Recovery from "./Recovery";
|
import Recovery from "./Recovery";
|
||||||
import Redeem from "./Redeem";
|
import Redeem from "./Redeem";
|
||||||
import Send from "./Send";
|
|
||||||
import Source from "./Source";
|
|
||||||
import Target from "./Target";
|
|
||||||
import SourcePreview from "./SourcePreview";
|
|
||||||
import TargetPreview from "./TargetPreview";
|
|
||||||
import SendPreview from "./SendPreview";
|
|
||||||
import RedeemPreview from "./RedeemPreview";
|
import RedeemPreview from "./RedeemPreview";
|
||||||
|
import Send from "./Send";
|
||||||
|
import SendPreview from "./SendPreview";
|
||||||
|
import Source from "./Source";
|
||||||
|
import SourcePreview from "./SourcePreview";
|
||||||
|
import Target from "./Target";
|
||||||
|
import TargetPreview from "./TargetPreview";
|
||||||
// TODO: ensure that both wallets are connected to the same known network
|
// TODO: ensure that both wallets are connected to the same known network
|
||||||
// TODO: loaders and such, navigation block?
|
// TODO: loaders and such, navigation block?
|
||||||
// TODO: refresh displayed token amount after transfer somehow, could be resolved by having different components appear
|
// TODO: refresh displayed token amount after transfer somehow, could be resolved by having different components appear
|
||||||
|
@ -49,6 +50,7 @@ function Transfer() {
|
||||||
const isSending = useSelector(selectTransferIsSending);
|
const isSending = useSelector(selectTransferIsSending);
|
||||||
const isSendComplete = useSelector(selectTransferIsSendComplete);
|
const isSendComplete = useSelector(selectTransferIsSendComplete);
|
||||||
const isRedeeming = useSelector(selectTransferIsRedeeming);
|
const isRedeeming = useSelector(selectTransferIsRedeeming);
|
||||||
|
const isRedeemComplete = useSelector(selectTransferIsRedeemComplete);
|
||||||
const preventNavigation = isSending || isSendComplete || isRedeeming;
|
const preventNavigation = isSending || isSendComplete || isRedeeming;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (preventNavigation) {
|
if (preventNavigation) {
|
||||||
|
@ -65,7 +67,10 @@ function Transfer() {
|
||||||
orientation="vertical"
|
orientation="vertical"
|
||||||
className={classes.rootContainer}
|
className={classes.rootContainer}
|
||||||
>
|
>
|
||||||
<Step expanded={activeStep >= 0} disabled={preventNavigation}>
|
<Step
|
||||||
|
expanded={activeStep >= 0}
|
||||||
|
disabled={preventNavigation || isRedeemComplete}
|
||||||
|
>
|
||||||
<StepButton onClick={() => dispatch(setStep(0))}>Source</StepButton>
|
<StepButton onClick={() => dispatch(setStep(0))}>Source</StepButton>
|
||||||
<StepContent>
|
<StepContent>
|
||||||
{activeStep === 0 ? (
|
{activeStep === 0 ? (
|
||||||
|
@ -75,13 +80,16 @@ function Transfer() {
|
||||||
)}
|
)}
|
||||||
</StepContent>
|
</StepContent>
|
||||||
</Step>
|
</Step>
|
||||||
<Step expanded={activeStep >= 1} disabled={preventNavigation}>
|
<Step
|
||||||
|
expanded={activeStep >= 1}
|
||||||
|
disabled={preventNavigation || isRedeemComplete}
|
||||||
|
>
|
||||||
<StepButton onClick={() => dispatch(setStep(1))}>Target</StepButton>
|
<StepButton onClick={() => dispatch(setStep(1))}>Target</StepButton>
|
||||||
<StepContent>
|
<StepContent>
|
||||||
{activeStep === 1 ? <Target /> : <TargetPreview />}
|
{activeStep === 1 ? <Target /> : <TargetPreview />}
|
||||||
</StepContent>
|
</StepContent>
|
||||||
</Step>
|
</Step>
|
||||||
<Step expanded={activeStep >= 2}>
|
<Step expanded={activeStep >= 2} disabled={isSendComplete}>
|
||||||
<StepButton onClick={() => dispatch(setStep(2))}>
|
<StepButton onClick={() => dispatch(setStep(2))}>
|
||||||
Send tokens
|
Send tokens
|
||||||
</StepButton>
|
</StepButton>
|
||||||
|
@ -97,7 +105,7 @@ function Transfer() {
|
||||||
Redeem tokens
|
Redeem tokens
|
||||||
</StepButton>
|
</StepButton>
|
||||||
<StepContent>
|
<StepContent>
|
||||||
{activeStep === 3 ? <Redeem /> : <RedeemPreview />}
|
{isRedeemComplete ? <RedeemPreview /> : <Redeem />}
|
||||||
</StepContent>
|
</StepContent>
|
||||||
</Step>
|
</Step>
|
||||||
</Stepper>
|
</Stepper>
|
||||||
|
|
|
@ -31,7 +31,7 @@ import {
|
||||||
ParsedTokenAccount,
|
ParsedTokenAccount,
|
||||||
receiveSourceParsedTokenAccounts,
|
receiveSourceParsedTokenAccounts,
|
||||||
} from "../store/transferSlice";
|
} from "../store/transferSlice";
|
||||||
import { COVALENT_GET_TOKENS_URL, SOLANA_HOST } from "../utils/consts";
|
import { CLUSTER, COVALENT_GET_TOKENS_URL, SOLANA_HOST } from "../utils/consts";
|
||||||
import {
|
import {
|
||||||
decodeMetadata,
|
decodeMetadata,
|
||||||
getMetadataAddress,
|
getMetadataAddress,
|
||||||
|
@ -128,8 +128,7 @@ const getEthereumAccountsCovalent = async (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const environment =
|
const environment = CLUSTER === "testnet" ? ENV.Testnet : ENV.MainnetBeta;
|
||||||
process.env.REACT_APP_CLUSTER === "testnet" ? ENV.Testnet : ENV.MainnetBeta;
|
|
||||||
|
|
||||||
const getMetaplexData = async (mintAddresses: string[]) => {
|
const getMetaplexData = async (mintAddresses: string[]) => {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
@ -176,6 +175,7 @@ const getSolanaParsedTokenAccounts = (
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
(result) => {
|
(result) => {
|
||||||
|
console.log(result);
|
||||||
const mappedItems = result.value.map((item) =>
|
const mappedItems = result.value.map((item) =>
|
||||||
createParsedTokenAccountFromInfo(item.pubkey, item.account)
|
createParsedTokenAccountFromInfo(item.pubkey, item.account)
|
||||||
);
|
);
|
||||||
|
|
|
@ -24,7 +24,7 @@ import {
|
||||||
selectTransferIsRedeeming,
|
selectTransferIsRedeeming,
|
||||||
selectTransferTargetChain,
|
selectTransferTargetChain,
|
||||||
} from "../store/selectors";
|
} from "../store/selectors";
|
||||||
import { reset, setIsRedeeming } from "../store/transferSlice";
|
import { setIsRedeeming, setRedeemTx } from "../store/transferSlice";
|
||||||
import {
|
import {
|
||||||
ETH_TOKEN_BRIDGE_ADDRESS,
|
ETH_TOKEN_BRIDGE_ADDRESS,
|
||||||
SOLANA_HOST,
|
SOLANA_HOST,
|
||||||
|
@ -43,8 +43,14 @@ async function eth(
|
||||||
) {
|
) {
|
||||||
dispatch(setIsRedeeming(true));
|
dispatch(setIsRedeeming(true));
|
||||||
try {
|
try {
|
||||||
await redeemOnEth(ETH_TOKEN_BRIDGE_ADDRESS, signer, signedVAA);
|
const receipt = await redeemOnEth(
|
||||||
dispatch(reset());
|
ETH_TOKEN_BRIDGE_ADDRESS,
|
||||||
|
signer,
|
||||||
|
signedVAA
|
||||||
|
);
|
||||||
|
dispatch(
|
||||||
|
setRedeemTx({ id: receipt.transactionHash, block: receipt.blockNumber })
|
||||||
|
);
|
||||||
enqueueSnackbar("Transaction confirmed", { variant: "success" });
|
enqueueSnackbar("Transaction confirmed", { variant: "success" });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
enqueueSnackbar(parseError(e), { variant: "error" });
|
enqueueSnackbar(parseError(e), { variant: "error" });
|
||||||
|
@ -78,8 +84,9 @@ async function solana(
|
||||||
payerAddress,
|
payerAddress,
|
||||||
signedVAA
|
signedVAA
|
||||||
);
|
);
|
||||||
await signSendAndConfirm(wallet, connection, transaction);
|
const txid = await signSendAndConfirm(wallet, connection, transaction);
|
||||||
dispatch(reset());
|
// TODO: didn't want to make an info call we didn't need, can we get the block without it by modifying the above call?
|
||||||
|
dispatch(setRedeemTx({ id: txid, block: 1 }));
|
||||||
enqueueSnackbar("Transaction confirmed", { variant: "success" });
|
enqueueSnackbar("Transaction confirmed", { variant: "success" });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
enqueueSnackbar(parseError(e), { variant: "error" });
|
enqueueSnackbar(parseError(e), { variant: "error" });
|
||||||
|
@ -100,11 +107,13 @@ async function terra(
|
||||||
wallet.terraAddress,
|
wallet.terraAddress,
|
||||||
signedVAA
|
signedVAA
|
||||||
);
|
);
|
||||||
await wallet.post({
|
const result = await wallet.post({
|
||||||
msgs: [msg],
|
msgs: [msg],
|
||||||
memo: "Wormhole - Complete Transfer",
|
memo: "Wormhole - Complete Transfer",
|
||||||
});
|
});
|
||||||
dispatch(reset());
|
dispatch(
|
||||||
|
setRedeemTx({ id: result.result.txhash, block: result.result.height })
|
||||||
|
);
|
||||||
enqueueSnackbar("Transaction confirmed", { variant: "success" });
|
enqueueSnackbar("Transaction confirmed", { variant: "success" });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
enqueueSnackbar(parseError(e), { variant: "error" });
|
enqueueSnackbar(parseError(e), { variant: "error" });
|
||||||
|
|
|
@ -143,7 +143,6 @@ async function solana(
|
||||||
throw new Error("An error occurred while fetching the transaction info");
|
throw new Error("An error occurred while fetching the transaction info");
|
||||||
}
|
}
|
||||||
dispatch(setTransferTx({ id: txid, block: info.slot }));
|
dispatch(setTransferTx({ id: txid, block: info.slot }));
|
||||||
enqueueSnackbar("Transaction confirmed", { variant: "success" });
|
|
||||||
const sequence = parseSequenceFromLogSolana(info);
|
const sequence = parseSequenceFromLogSolana(info);
|
||||||
const emitterAddress = await getEmitterAddressSolana(
|
const emitterAddress = await getEmitterAddressSolana(
|
||||||
SOL_TOKEN_BRIDGE_ADDRESS
|
SOL_TOKEN_BRIDGE_ADDRESS
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { useConnectedWallet } from "@terra-money/wallet-provider";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
|
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
|
||||||
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
||||||
import { ETH_NETWORK_CHAIN_ID } from "../utils/consts";
|
import { CLUSTER, ETH_NETWORK_CHAIN_ID } from "../utils/consts";
|
||||||
|
|
||||||
const createWalletStatus = (isReady: boolean, statusMessage: string = "") => ({
|
const createWalletStatus = (isReady: boolean, statusMessage: string = "") => ({
|
||||||
isReady,
|
isReady,
|
||||||
|
@ -45,7 +45,7 @@ function useIsWalletReady(chainId: ChainId): {
|
||||||
} else {
|
} else {
|
||||||
return createWalletStatus(
|
return createWalletStatus(
|
||||||
false,
|
false,
|
||||||
`Wallet is not connected to ${process.env.REACT_APP_CLUSTER}. Expected Chain ID: ${ETH_NETWORK_CHAIN_ID}`
|
`Wallet is not connected to ${CLUSTER}. Expected Chain ID: ${ETH_NETWORK_CHAIN_ID}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,8 @@ export const selectTransferIsSending = (state: RootState) =>
|
||||||
state.transfer.isSending;
|
state.transfer.isSending;
|
||||||
export const selectTransferIsRedeeming = (state: RootState) =>
|
export const selectTransferIsRedeeming = (state: RootState) =>
|
||||||
state.transfer.isRedeeming;
|
state.transfer.isRedeeming;
|
||||||
|
export const selectTransferRedeemTx = (state: RootState) =>
|
||||||
|
state.transfer.redeemTx;
|
||||||
export const selectTransferSourceError = (
|
export const selectTransferSourceError = (
|
||||||
state: RootState
|
state: RootState
|
||||||
): string | undefined => {
|
): string | undefined => {
|
||||||
|
@ -158,6 +160,8 @@ export const selectTransferIsTargetComplete = (state: RootState) =>
|
||||||
!selectTransferTargetError(state);
|
!selectTransferTargetError(state);
|
||||||
export const selectTransferIsSendComplete = (state: RootState) =>
|
export const selectTransferIsSendComplete = (state: RootState) =>
|
||||||
!!selectTransferSignedVAAHex(state);
|
!!selectTransferSignedVAAHex(state);
|
||||||
|
export const selectTransferIsRedeemComplete = (state: RootState) =>
|
||||||
|
!!selectTransferRedeemTx(state);
|
||||||
export const selectTransferShouldLockFields = (state: RootState) =>
|
export const selectTransferShouldLockFields = (state: RootState) =>
|
||||||
selectTransferIsSending(state) || selectTransferIsSendComplete(state);
|
selectTransferIsSending(state) || selectTransferIsSendComplete(state);
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ export interface TransferState {
|
||||||
signedVAAHex: string | undefined;
|
signedVAAHex: string | undefined;
|
||||||
isSending: boolean;
|
isSending: boolean;
|
||||||
isRedeeming: boolean;
|
isRedeeming: boolean;
|
||||||
|
redeemTx: Transaction | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: TransferState = {
|
const initialState: TransferState = {
|
||||||
|
@ -67,6 +68,7 @@ const initialState: TransferState = {
|
||||||
signedVAAHex: undefined,
|
signedVAAHex: undefined,
|
||||||
isSending: false,
|
isSending: false,
|
||||||
isRedeeming: false,
|
isRedeeming: false,
|
||||||
|
redeemTx: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const transferSlice = createSlice({
|
export const transferSlice = createSlice({
|
||||||
|
@ -176,6 +178,9 @@ export const transferSlice = createSlice({
|
||||||
setIsRedeeming: (state, action: PayloadAction<boolean>) => {
|
setIsRedeeming: (state, action: PayloadAction<boolean>) => {
|
||||||
state.isRedeeming = action.payload;
|
state.isRedeeming = action.payload;
|
||||||
},
|
},
|
||||||
|
setRedeemTx: (state, action: PayloadAction<Transaction>) => {
|
||||||
|
state.redeemTx = action.payload;
|
||||||
|
},
|
||||||
reset: () => initialState,
|
reset: () => initialState,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -199,6 +204,7 @@ export const {
|
||||||
setSignedVAAHex,
|
setSignedVAAHex,
|
||||||
setIsSending,
|
setIsSending,
|
||||||
setIsRedeeming,
|
setIsRedeeming,
|
||||||
|
setRedeemTx,
|
||||||
reset,
|
reset,
|
||||||
} = transferSlice.actions;
|
} = transferSlice.actions;
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,19 @@ import {
|
||||||
import { clusterApiUrl } from "@solana/web3.js";
|
import { clusterApiUrl } from "@solana/web3.js";
|
||||||
import { getAddress } from "ethers/lib/utils";
|
import { getAddress } from "ethers/lib/utils";
|
||||||
|
|
||||||
|
export type Cluster = "devnet" | "testnet" | "mainnet";
|
||||||
|
export const CLUSTER: Cluster =
|
||||||
|
process.env.REACT_APP_CLUSTER === "mainnet"
|
||||||
|
? "mainnet"
|
||||||
|
: process.env.REACT_APP_CLUSTER === "testnet"
|
||||||
|
? "testnet"
|
||||||
|
: "devnet";
|
||||||
export interface ChainInfo {
|
export interface ChainInfo {
|
||||||
id: ChainId;
|
id: ChainId;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
export const CHAINS =
|
export const CHAINS =
|
||||||
process.env.REACT_APP_CLUSTER === "testnet"
|
CLUSTER === "testnet"
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
id: CHAIN_ID_ETH,
|
id: CHAIN_ID_ETH,
|
||||||
|
@ -48,49 +55,43 @@ export const CHAINS_BY_ID: ChainsById = CHAINS.reduce((obj, chain) => {
|
||||||
return obj;
|
return obj;
|
||||||
}, {} as ChainsById);
|
}, {} as ChainsById);
|
||||||
export const WORMHOLE_RPC_HOST =
|
export const WORMHOLE_RPC_HOST =
|
||||||
process.env.REACT_APP_CLUSTER === "testnet"
|
CLUSTER === "testnet"
|
||||||
? "https://wormhole-v2-testnet-api.certus.one"
|
? "https://wormhole-v2-testnet-api.certus.one"
|
||||||
: "http://localhost:8080";
|
: "http://localhost:8080";
|
||||||
export const ETH_NETWORK_CHAIN_ID =
|
export const ETH_NETWORK_CHAIN_ID =
|
||||||
process.env.REACT_APP_CLUSTER === "mainnet"
|
CLUSTER === "mainnet" ? 1 : CLUSTER === "testnet" ? 5 : 1337;
|
||||||
? 1
|
|
||||||
: process.env.REACT_APP_CLUSTER === "testnet"
|
|
||||||
? 5
|
|
||||||
: 1337;
|
|
||||||
export const SOLANA_HOST =
|
export const SOLANA_HOST =
|
||||||
process.env.REACT_APP_CLUSTER === "testnet"
|
CLUSTER === "testnet" ? clusterApiUrl("testnet") : "http://localhost:8899";
|
||||||
? clusterApiUrl("testnet")
|
|
||||||
: "http://localhost:8899";
|
|
||||||
export const TERRA_HOST = {
|
export const TERRA_HOST = {
|
||||||
URL: "http://localhost:1317",
|
URL: "http://localhost:1317",
|
||||||
chainID: "columbus-4",
|
chainID: "columbus-4",
|
||||||
name: "localterra",
|
name: "localterra",
|
||||||
};
|
};
|
||||||
export const ETH_TEST_TOKEN_ADDRESS = getAddress(
|
export const ETH_TEST_TOKEN_ADDRESS = getAddress(
|
||||||
process.env.REACT_APP_CLUSTER === "testnet"
|
CLUSTER === "testnet"
|
||||||
? "0xcEE940033DA197F551BBEdED7F4aA55Ee55C582B"
|
? "0xcEE940033DA197F551BBEdED7F4aA55Ee55C582B"
|
||||||
: "0x67B5656d60a809915323Bf2C40A8bEF15A152e3e"
|
: "0x67B5656d60a809915323Bf2C40A8bEF15A152e3e"
|
||||||
);
|
);
|
||||||
export const ETH_BRIDGE_ADDRESS = getAddress(
|
export const ETH_BRIDGE_ADDRESS = getAddress(
|
||||||
process.env.REACT_APP_CLUSTER === "testnet"
|
CLUSTER === "testnet"
|
||||||
? "0x44F3e7c20850B3B5f3031114726A9240911D912a"
|
? "0x44F3e7c20850B3B5f3031114726A9240911D912a"
|
||||||
: "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
|
: "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
|
||||||
);
|
);
|
||||||
export const ETH_TOKEN_BRIDGE_ADDRESS = getAddress(
|
export const ETH_TOKEN_BRIDGE_ADDRESS = getAddress(
|
||||||
process.env.REACT_APP_CLUSTER === "testnet"
|
CLUSTER === "testnet"
|
||||||
? "0xa6CDAddA6e4B6704705b065E01E52e2486c0FBf6"
|
? "0xa6CDAddA6e4B6704705b065E01E52e2486c0FBf6"
|
||||||
: "0x0290FB167208Af455bB137780163b7B7a9a10C16"
|
: "0x0290FB167208Af455bB137780163b7B7a9a10C16"
|
||||||
);
|
);
|
||||||
export const SOL_TEST_TOKEN_ADDRESS =
|
export const SOL_TEST_TOKEN_ADDRESS =
|
||||||
process.env.REACT_APP_CLUSTER === "testnet"
|
CLUSTER === "testnet"
|
||||||
? "6uzMjLkcTwhYo5Fwx9DtVtQ7VRrCQ7bTUd7rHXTiPDXp"
|
? "6uzMjLkcTwhYo5Fwx9DtVtQ7VRrCQ7bTUd7rHXTiPDXp"
|
||||||
: "2WDq7wSs9zYrpx2kbHDA4RUTRch2CCTP6ZWaH4GNfnQQ";
|
: "2WDq7wSs9zYrpx2kbHDA4RUTRch2CCTP6ZWaH4GNfnQQ";
|
||||||
export const SOL_BRIDGE_ADDRESS =
|
export const SOL_BRIDGE_ADDRESS =
|
||||||
process.env.REACT_APP_CLUSTER === "testnet"
|
CLUSTER === "testnet"
|
||||||
? "Brdguy7BmNB4qwEbcqqMbyV5CyJd2sxQNUn6NEpMSsUb"
|
? "Brdguy7BmNB4qwEbcqqMbyV5CyJd2sxQNUn6NEpMSsUb"
|
||||||
: "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o";
|
: "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o";
|
||||||
export const SOL_TOKEN_BRIDGE_ADDRESS =
|
export const SOL_TOKEN_BRIDGE_ADDRESS =
|
||||||
process.env.REACT_APP_CLUSTER === "testnet"
|
CLUSTER === "testnet"
|
||||||
? "A4Us8EhCC76XdGAN17L4KpRNEK423nMivVHZzZqFqqBg"
|
? "A4Us8EhCC76XdGAN17L4KpRNEK423nMivVHZzZqFqqBg"
|
||||||
: "B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE";
|
: "B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE";
|
||||||
export const TERRA_TEST_TOKEN_ADDRESS =
|
export const TERRA_TEST_TOKEN_ADDRESS =
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { getIsWrappedAssetSol as getIsWrappedAssetSolTx } from "@certusone/wormhole-sdk";
|
|
||||||
import { Connection } from "@solana/web3.js";
|
|
||||||
import { SOLANA_HOST, SOL_TOKEN_BRIDGE_ADDRESS } from "./consts";
|
|
||||||
|
|
||||||
export async function getIsWrappedAssetSol(mintAddress: string) {
|
|
||||||
// TODO: share connection in context?
|
|
||||||
const connection = new Connection(SOLANA_HOST, "confirmed");
|
|
||||||
return await getIsWrappedAssetSolTx(
|
|
||||||
connection,
|
|
||||||
SOL_TOKEN_BRIDGE_ADDRESS,
|
|
||||||
mintAddress
|
|
||||||
);
|
|
||||||
}
|
|
Loading…
Reference in New Issue