diff --git a/bridge_ui/src/components/TokenSelectors/EvmTokenPicker.tsx b/bridge_ui/src/components/TokenSelectors/EvmTokenPicker.tsx
index a5e04cd4..b3b42fd3 100644
--- a/bridge_ui/src/components/TokenSelectors/EvmTokenPicker.tsx
+++ b/bridge_ui/src/components/TokenSelectors/EvmTokenPicker.tsx
@@ -146,36 +146,16 @@ export default function EvmTokenPicker(
} catch (e) {
//For now, just swallow this one.
}
- let newAccount = null;
- try {
- //Covalent balances tend to be stale, so we make an attempt to correct it at selection time.
- if (!account.isNativeAsset) {
- newAccount = await getAddress(account.mintKey, account.tokenId);
- newAccount = { ...account, ...newAccount }; //We spread over the old account so we don't lose the logo, uri, or other useful info we got from covalent.
- } else {
- newAccount = account;
- }
- } catch (e) {
- //swallow
- console.log(e);
- }
- if (!newAccount) {
- //Must reject otherwise downstream checks relying on the balance may fail.
- //An error is thrown so that the code above us will display the message.
- throw new Error(
- "Unable to retrieve required information about this token. Ensure your wallet is connected, then refresh the list."
- );
- }
const migration = isMigrationEligible(account.publicKey);
if (v1 === true && !migration) {
throw new Error(
"Wormhole v1 assets cannot be transferred with this bridge."
);
}
- onChange(newAccount);
+ onChange(account);
return Promise.resolve();
},
- [chainId, onChange, provider, isMigrationEligible, getAddress]
+ [chainId, onChange, provider, isMigrationEligible]
);
const RenderComp = useCallback(
diff --git a/bridge_ui/src/components/TokenSelectors/TokenPicker.tsx b/bridge_ui/src/components/TokenSelectors/TokenPicker.tsx
index ea5706f4..97d525f8 100644
--- a/bridge_ui/src/components/TokenSelectors/TokenPicker.tsx
+++ b/bridge_ui/src/components/TokenSelectors/TokenPicker.tsx
@@ -7,7 +7,9 @@ import {
Dialog,
DialogContent,
DialogTitle,
+ Divider,
IconButton,
+ Link,
List,
ListItem,
makeStyles,
@@ -15,11 +17,16 @@ import {
Tooltip,
Typography,
} from "@material-ui/core";
+import { InfoOutlined, Launch } from "@material-ui/icons";
import KeyboardArrowDownIcon from "@material-ui/icons/KeyboardArrowDown";
import RefreshIcon from "@material-ui/icons/Refresh";
import { Alert } from "@material-ui/lab";
import React, { useCallback, useEffect, useMemo, useState } from "react";
+import { useSelector } from "react-redux";
+import useMarketsMap from "../../hooks/useMarketsMap";
import { NFTParsedTokenAccount } from "../../store/nftSlice";
+import { selectTransferTargetChain } from "../../store/selectors";
+import { AVAILABLE_MARKETS_URL, CHAINS_BY_ID } from "../../utils/consts";
import { shortenAddress } from "../../utils/solana";
import NFTViewer from "./NFTViewer";
@@ -62,6 +69,11 @@ const useStyles = makeStyles((theme) =>
"&$tokenImageContainer": {
maxWidth: 40,
},
+ "&$tokenMarketsList": {
+ marginTop: theme.spacing(-0.5),
+ marginLeft: 0,
+ flexBasis: "100%",
+ },
"&:last-child": {
textAlign: "right",
},
@@ -78,6 +90,15 @@ const useStyles = makeStyles((theme) =>
tokenImage: {
maxHeight: "2.5rem", //Eyeballing this based off the text size
},
+ tokenMarketsList: {
+ order: 1,
+ textAlign: "left",
+ width: "100%",
+ "& > .MuiButton-root": {
+ marginTop: theme.spacing(1),
+ marginRight: theme.spacing(1),
+ },
+ },
migrationAlert: {
width: "100%",
"& .MuiAlert-message": {
@@ -107,12 +128,17 @@ export const balancePretty = (uiString: string) => {
}
};
+const noClickThrough = (e: any) => {
+ e.stopPropagation();
+};
+
export const BasicAccountRender = (
- account: NFTParsedTokenAccount,
+ account: MarketParsedTokenAccount,
isMigrationEligible: (address: string) => boolean,
nft: boolean,
displayBalance?: (account: NFTParsedTokenAccount) => boolean
) => {
+ const { data: marketsData } = useMarketsMap(false);
const classes = useStyles();
const mintPrettyString = shortenAddress(account.mintKey);
const uri = nft ? account.image_256 : account.logo || account.uri;
@@ -139,6 +165,27 @@ export const BasicAccountRender = (
const tokenContent = (
+ {account.markets ? (
+
+ {account.markets.map((market) =>
+ marketsData?.markets?.[market] ? (
+ }
+ href={marketsData.markets[market].link}
+ target="_blank"
+ rel="noopener noreferrer"
+ onClick={noClickThrough}
+ >
+ {marketsData.markets[market].name}
+
+ ) : null
+ )}
+
+ ) : null}
{uri &&
}
@@ -185,6 +232,10 @@ export const BasicAccountRender = (
: tokenContent;
};
+interface MarketParsedTokenAccount extends NFTParsedTokenAccount {
+ markets?: string[];
+}
+
export default function TokenPicker({
value,
options,
@@ -229,6 +280,9 @@ export default function TokenPicker({
const [dialogIsOpen, setDialogIsOpen] = useState(false);
const [selectionError, setSelectionError] = useState("");
+ const targetChain = useSelector(selectTransferTargetChain);
+ const { data: marketsData } = useMarketsMap(true);
+
const openDialog = useCallback(() => {
setHolderString("");
setSelectionError("");
@@ -242,16 +296,31 @@ export default function TokenPicker({
const handleSelectOption = useCallback(
async (option: NFTParsedTokenAccount) => {
setSelectionError("");
- onChange(option).then(
- () => {
- closeDialog();
- },
- (error) => {
- setSelectionError(error?.message || "Error verifying the token.");
+ let newOption = null;
+ try {
+ //Covalent balances tend to be stale, so we make an attempt to correct it at selection time.
+ if (getAddress && !option.isNativeAsset) {
+ newOption = await getAddress(option.mintKey, option.tokenId);
+ newOption = {
+ ...option,
+ ...newOption,
+ // keep logo and uri from covalent / market list / etc (otherwise would be overwritten by undefined)
+ logo: option.logo || newOption.logo,
+ uri: option.uri || newOption.uri,
+ } as NFTParsedTokenAccount;
+ } else {
+ newOption = option;
}
- );
+ await onChange(newOption);
+ closeDialog();
+ } catch (e) {
+ console.error(e);
+ setSelectionError(
+ "Unable to retrieve required information about this token. Ensure your wallet is connected, then refresh the list."
+ );
+ }
},
- [onChange, closeDialog]
+ [getAddress, onChange, closeDialog]
);
const resetAccountsWrapper = useCallback(() => {
@@ -261,8 +330,8 @@ export default function TokenPicker({
resetAccounts && resetAccounts();
}, [resetAccounts]);
- const filteredOptions = useMemo(() => {
- return options.filter((option: NFTParsedTokenAccount) => {
+ const searchFilter = useCallback(
+ (option: NFTParsedTokenAccount) => {
if (!holderString) {
return true;
}
@@ -277,8 +346,61 @@ export default function TokenPicker({
).toLowerCase();
const searchString = holderString.toLowerCase();
return optionString.includes(searchString);
- });
- }, [holderString, options]);
+ },
+ [holderString]
+ );
+
+ const marketChainTokens = marketsData?.tokens?.[chainId];
+ const featuredMarkets = marketsData?.tokenMarkets?.[chainId]?.[targetChain];
+
+ const featuredOptions = useMemo(() => {
+ // only tokens have featured markets
+ if (!nft && featuredMarkets) {
+ const ownedMarketTokens = options
+ .filter(
+ (option: NFTParsedTokenAccount) => featuredMarkets?.[option.mintKey]
+ )
+ .map(
+ (option) =>
+ ({
+ ...option,
+ markets: featuredMarkets[option.mintKey].markets,
+ } as MarketParsedTokenAccount)
+ );
+ return [
+ ...ownedMarketTokens,
+ ...Object.keys(featuredMarkets)
+ .filter(
+ (mintKey) =>
+ !ownedMarketTokens.find((option) => option.mintKey === mintKey)
+ )
+ .map(
+ (mintKey) =>
+ ({
+ amount: "0",
+ decimals: 0,
+ markets: featuredMarkets[mintKey].markets,
+ mintKey,
+ publicKey: "",
+ uiAmount: 0,
+ uiAmountString: "0", // if we can't look up by address, we can select the market that isn't in the list of holdings, but can't proceed since the balance will be 0
+ symbol: marketChainTokens?.[mintKey]?.symbol,
+ logo: marketChainTokens?.[mintKey]?.logo,
+ } as MarketParsedTokenAccount)
+ ),
+ ].filter(searchFilter);
+ }
+ return [];
+ }, [nft, marketChainTokens, featuredMarkets, options, searchFilter]);
+
+ const nonFeaturedOptions = useMemo(() => {
+ return options.filter(
+ (option: NFTParsedTokenAccount) =>
+ searchFilter(option) &&
+ // only tokens have featured markets
+ (nft || !featuredMarkets?.[option.mintKey])
+ );
+ }, [nft, options, featuredMarkets, searchFilter]);
const localFind = useCallback(
(address: string, tokenIdHolderString: string) => {
@@ -383,6 +505,17 @@ export default function TokenPicker({
+
+ You should always check for markets and liquidity before sending
+ tokens.{" "}
+
+ Click here to see available markets for wrapped tokens.
+
+
- {filteredOptions.map((option) => {
+ ) : (
+
+ {featuredOptions.length ? (
+ <>
+
+ Featured {CHAINS_BY_ID[chainId].name} >{" "}
+ {CHAINS_BY_ID[targetChain].name} markets{" "}
+
+
+
+
+ {featuredOptions.map((option) => {
+ return (
+ handleSelectOption(option)}
+ key={
+ option.publicKey +
+ option.mintKey +
+ (option.tokenId || "")
+ }
+ >
+
+
+ );
+ })}
+ {nonFeaturedOptions.length ? (
+ <>
+
+
+ Other Assets
+
+ >
+ ) : null}
+ >
+ ) : null}
+ {nonFeaturedOptions.map((option) => {
return (
handleSelectOption(option)}
key={
@@ -420,11 +594,12 @@ export default function TokenPicker({
);
})}
+ {featuredOptions.length || nonFeaturedOptions.length ? null : (
+
+ No results found
+
+ )}
- ) : (
-
- No results found
-
)}
diff --git a/bridge_ui/src/components/Transfer/Source.tsx b/bridge_ui/src/components/Transfer/Source.tsx
index a04dbb6b..21baa1bf 100644
--- a/bridge_ui/src/components/Transfer/Source.tsx
+++ b/bridge_ui/src/components/Transfer/Source.tsx
@@ -4,12 +4,12 @@ import {
CHAIN_ID_SOLANA,
} from "@certusone/wormhole-sdk";
import { getAddress } from "@ethersproject/address";
-import { Button, makeStyles } from "@material-ui/core";
-import { Link } from "react-router-dom";
-import { VerifiedUser } from "@material-ui/icons";
-import { useCallback } from "react";
+import { Button, makeStyles, Typography } from "@material-ui/core";
+import { ArrowForward, VerifiedUser } from "@material-ui/icons";
+import { useCallback, useMemo } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useHistory } from "react-router";
+import { Link } from "react-router-dom";
import useIsWalletReady from "../../hooks/useIsWalletReady";
import {
selectTransferAmount,
@@ -19,11 +19,13 @@ import {
selectTransferSourceChain,
selectTransferSourceError,
selectTransferSourceParsedTokenAccount,
+ selectTransferTargetChain,
} from "../../store/selectors";
import {
incrementStep,
setAmount,
setSourceChain,
+ setTargetChain,
} from "../../store/transferSlice";
import {
BSC_MIGRATION_ASSET_MAP,
@@ -40,6 +42,24 @@ import StepDescription from "../StepDescription";
import { TokenSelector } from "../TokenSelectors/SourceTokenSelector";
const useStyles = makeStyles((theme) => ({
+ chainSelectWrapper: {
+ display: "flex",
+ alignItems: "center",
+ [theme.breakpoints.down("sm")]: {
+ flexDirection: "column",
+ },
+ },
+ chainSelectContainer: {
+ flexBasis: "100%",
+ [theme.breakpoints.down("sm")]: {
+ width: "100%",
+ },
+ },
+ chainSelectArrow: {
+ position: "relative",
+ top: "12px",
+ [theme.breakpoints.down("sm")]: { transform: "rotate(90deg)" },
+ },
transferField: {
marginTop: theme.spacing(5),
},
@@ -50,6 +70,11 @@ function Source() {
const dispatch = useDispatch();
const history = useHistory();
const sourceChain = useSelector(selectTransferSourceChain);
+ const targetChain = useSelector(selectTransferTargetChain);
+ const targetChainOptions = useMemo(
+ () => CHAINS.filter((c) => c.id !== sourceChain),
+ [sourceChain]
+ );
const parsedTokenAccount = useSelector(
selectTransferSourceParsedTokenAccount
);
@@ -91,6 +116,12 @@ function Source() {
},
[dispatch]
);
+ const handleTargetChange = useCallback(
+ (event) => {
+ dispatch(setTargetChain(event.target.value));
+ },
+ [dispatch]
+ );
const handleAmountChange = useCallback(
(event) => {
dispatch(setAmount(event.target.value));
@@ -124,15 +155,35 @@ function Source() {
-
+
+
+ Source
+
+
+
+
+ Target
+
+
+
{isReady || uiAmountString ? (
diff --git a/bridge_ui/src/components/Transfer/Target.tsx b/bridge_ui/src/components/Transfer/Target.tsx
index 506a0691..be39ac55 100644
--- a/bridge_ui/src/components/Transfer/Target.tsx
+++ b/bridge_ui/src/components/Transfer/Target.tsx
@@ -125,7 +125,7 @@ function Target() {
fullWidth
value={targetChain}
onChange={handleTargetChange}
- disabled={shouldLockFields}
+ disabled={true}
chains={chains}
/>
diff --git a/bridge_ui/src/hooks/useMarketsMap.ts b/bridge_ui/src/hooks/useMarketsMap.ts
new file mode 100644
index 00000000..f7598b3c
--- /dev/null
+++ b/bridge_ui/src/hooks/useMarketsMap.ts
@@ -0,0 +1,72 @@
+import { ChainId } from "@certusone/wormhole-sdk";
+import { Dispatch } from "@reduxjs/toolkit";
+import axios from "axios";
+import { useEffect } from "react";
+import { useDispatch, useSelector } from "react-redux";
+import { DataWrapper } from "../store/helpers";
+import { selectMarketsMap } from "../store/selectors";
+import {
+ errorMarketsMap,
+ fetchMarketsMap,
+ receiveMarketsMap,
+} from "../store/tokenSlice";
+import { FEATURED_MARKETS_JSON_URL } from "../utils/consts";
+
+export type MarketsMap = {
+ markets?: {
+ [index: string]: {
+ name: string;
+ link: string;
+ };
+ };
+ tokens?: {
+ [key in ChainId]?: {
+ [index: string]: {
+ symbol: string;
+ logo: string;
+ };
+ };
+ };
+ tokenMarkets?: {
+ [key in ChainId]?: {
+ [key in ChainId]?: {
+ [index: string]: {
+ symbol: string;
+ logo: string;
+ markets: string[];
+ };
+ };
+ };
+ };
+};
+
+const useMarketsMap = (shouldFire: boolean): DataWrapper => {
+ const marketsMap = useSelector(selectMarketsMap);
+ const dispatch = useDispatch();
+ const internalShouldFire =
+ shouldFire &&
+ (marketsMap.data === undefined ||
+ (marketsMap.data === null && !marketsMap.isFetching));
+
+ useEffect(() => {
+ if (internalShouldFire) {
+ getMarketsMap(dispatch);
+ }
+ }, [internalShouldFire, dispatch]);
+
+ return marketsMap;
+};
+
+const getMarketsMap = (dispatch: Dispatch) => {
+ dispatch(fetchMarketsMap());
+ axios.get(FEATURED_MARKETS_JSON_URL).then(
+ (response) => {
+ dispatch(receiveMarketsMap(response.data as MarketsMap));
+ },
+ (error) => {
+ dispatch(errorMarketsMap("Failed to retrieve the Terra Token List."));
+ }
+ );
+};
+
+export default useMarketsMap;
diff --git a/bridge_ui/src/store/selectors.ts b/bridge_ui/src/store/selectors.ts
index cd544745..f4f0fa52 100644
--- a/bridge_ui/src/store/selectors.ts
+++ b/bridge_ui/src/store/selectors.ts
@@ -292,3 +292,7 @@ export const selectSolanaTokenMap = (state: RootState) => {
export const selectTerraTokenMap = (state: RootState) => {
return state.tokens.terraTokenMap;
};
+
+export const selectMarketsMap = (state: RootState) => {
+ return state.tokens.marketsMap;
+};
diff --git a/bridge_ui/src/store/tokenSlice.ts b/bridge_ui/src/store/tokenSlice.ts
index ee14ea9f..120b2a66 100644
--- a/bridge_ui/src/store/tokenSlice.ts
+++ b/bridge_ui/src/store/tokenSlice.ts
@@ -1,6 +1,7 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { TokenInfo } from "@solana/spl-token-registry";
import { TerraTokenMap } from "../hooks/useTerraTokenMap";
+import { MarketsMap } from "../hooks/useMarketsMap";
import {
DataWrapper,
errorDataWrapper,
@@ -12,11 +13,13 @@ import {
export interface TokenMetadataState {
solanaTokenMap: DataWrapper;
terraTokenMap: DataWrapper; //TODO make a decent type for this.
+ marketsMap: DataWrapper;
}
const initialState: TokenMetadataState = {
solanaTokenMap: getEmptyDataWrapper(),
terraTokenMap: getEmptyDataWrapper(),
+ marketsMap: getEmptyDataWrapper(),
};
export const tokenSlice = createSlice({
@@ -43,6 +46,16 @@ export const tokenSlice = createSlice({
state.terraTokenMap = errorDataWrapper(action.payload);
},
+ receiveMarketsMap: (state, action: PayloadAction) => {
+ state.marketsMap = receiveDataWrapper(action.payload);
+ },
+ fetchMarketsMap: (state) => {
+ state.marketsMap = fetchDataWrapper();
+ },
+ errorMarketsMap: (state, action: PayloadAction) => {
+ state.marketsMap = errorDataWrapper(action.payload);
+ },
+
reset: () => initialState,
},
});
@@ -54,6 +67,9 @@ export const {
receiveTerraTokenMap,
fetchTerraTokenMap,
errorTerraTokenMap,
+ receiveMarketsMap,
+ fetchMarketsMap,
+ errorMarketsMap,
reset,
} = tokenSlice.actions;
diff --git a/bridge_ui/src/utils/consts.ts b/bridge_ui/src/utils/consts.ts
index 363b00db..eac14e3f 100644
--- a/bridge_ui/src/utils/consts.ts
+++ b/bridge_ui/src/utils/consts.ts
@@ -136,9 +136,7 @@ export const WORMHOLE_RPC_HOSTS =
"https://wormhole-v2-mainnet-api.chainlayer.network",
]
: CLUSTER === "testnet"
- ? [
- "https://wormhole-v2-testnet-api.certus.one",
- ]
+ ? ["https://wormhole-v2-testnet-api.certus.one"]
: ["http://localhost:7071"];
export const ETH_NETWORK_CHAIN_ID =
CLUSTER === "mainnet" ? 1 : CLUSTER === "testnet" ? 5 : 1337;
@@ -159,7 +157,7 @@ export const SOLANA_HOST = process.env.REACT_APP_SOLANA_API_URL
: CLUSTER === "mainnet"
? clusterApiUrl("mainnet-beta")
: CLUSTER === "testnet"
- ? clusterApiUrl("testnet")
+ ? clusterApiUrl("devnet")
: "http://localhost:8899";
export const TERRA_HOST =
@@ -184,82 +182,82 @@ export const ETH_BRIDGE_ADDRESS = getAddress(
CLUSTER === "mainnet"
? "0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B"
: CLUSTER === "testnet"
- ? "0x44F3e7c20850B3B5f3031114726A9240911D912a"
+ ? "0xC0231E0957596A90004119f4254aff364f6f1002"
: "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
);
export const ETH_NFT_BRIDGE_ADDRESS = getAddress(
CLUSTER === "mainnet"
? "0x6FFd7EdE62328b3Af38FCD61461Bbfc52F5651fE"
: CLUSTER === "testnet"
- ? "0x26b4afb60d6c903165150c6f0aa14f8016be4aec" // TODO: test address
+ ? "0x5B78d166Fc3C2c99783B60b959dC35E316EBB5e7"
: "0x26b4afb60d6c903165150c6f0aa14f8016be4aec"
);
export const ETH_TOKEN_BRIDGE_ADDRESS = getAddress(
CLUSTER === "mainnet"
? "0x3ee18B2214AFF97000D974cf647E7C347E8fa585"
: CLUSTER === "testnet"
- ? "0xa6CDAddA6e4B6704705b065E01E52e2486c0FBf6"
+ ? "0xc59072C84ECD13DbF30856021C0a33868121Cb9d"
: "0x0290FB167208Af455bB137780163b7B7a9a10C16"
);
export const BSC_BRIDGE_ADDRESS = getAddress(
CLUSTER === "mainnet"
? "0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B"
: CLUSTER === "testnet"
- ? "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550" // TODO: test address
+ ? "0x61D9309dC73CcAC3c639aeC497A11320C5A72074"
: "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
);
export const BSC_NFT_BRIDGE_ADDRESS = getAddress(
CLUSTER === "mainnet"
? "0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE"
: CLUSTER === "testnet"
- ? "0x26b4afb60d6c903165150c6f0aa14f8016be4aec" // TODO: test address
+ ? "0x55A525D72f4b08762991e4ECDB1aDb5Ab55dFf37"
: "0x26b4afb60d6c903165150c6f0aa14f8016be4aec"
);
export const BSC_TOKEN_BRIDGE_ADDRESS = getAddress(
CLUSTER === "mainnet"
? "0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7"
: CLUSTER === "testnet"
- ? "0x0290FB167208Af455bB137780163b7B7a9a10C16" // TODO: test address
+ ? "0xC708B76f0C28040A0f852DbacB26375eDB071c1D"
: "0x0290FB167208Af455bB137780163b7B7a9a10C16"
);
export const POLYGON_BRIDGE_ADDRESS = getAddress(
CLUSTER === "mainnet"
? "0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7"
: CLUSTER === "testnet"
- ? "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550" // TODO: test address
+ ? "0x61D9309dC73CcAC3c639aeC497A11320C5A72074"
: "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
);
export const POLYGON_NFT_BRIDGE_ADDRESS = getAddress(
CLUSTER === "mainnet"
? "0x90BBd86a6Fe93D3bc3ed6335935447E75fAb7fCf"
: CLUSTER === "testnet"
- ? "0x26b4afb60d6c903165150c6f0aa14f8016be4aec" // TODO: test address
+ ? "0x55A525D72f4b08762991e4ECDB1aDb5Ab55dFf37"
: "0x26b4afb60d6c903165150c6f0aa14f8016be4aec"
);
export const POLYGON_TOKEN_BRIDGE_ADDRESS = getAddress(
CLUSTER === "mainnet"
? "0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE"
: CLUSTER === "testnet"
- ? "0x0290FB167208Af455bB137780163b7B7a9a10C16" // TODO: test address
+ ? "0xC708B76f0C28040A0f852DbacB26375eDB071c1D"
: "0x0290FB167208Af455bB137780163b7B7a9a10C16"
);
export const SOL_BRIDGE_ADDRESS =
CLUSTER === "mainnet"
? "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth"
: CLUSTER === "testnet"
- ? "Brdguy7BmNB4qwEbcqqMbyV5CyJd2sxQNUn6NEpMSsUb"
+ ? "FvXhjZdGJT4JdaTJHcPtvogBsc1kbgiFo3utK6mZZzdP"
: "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o";
export const SOL_NFT_BRIDGE_ADDRESS =
CLUSTER === "mainnet"
? "WnFt12ZrnzZrFZkt2xsNsaNWoQribnuQ5B5FrDbwDhD"
: CLUSTER === "testnet"
- ? "NFTWqJR8YnRVqPDvTJrYuLrQDitTG5AScqbeghi4zSA" // TODO: test address
+ ? "pnfZ3u1LPAaupt8YoZkxJkWUDoCZxs4XJkGibDQz7fW0"
: "NFTWqJR8YnRVqPDvTJrYuLrQDitTG5AScqbeghi4zSA";
export const SOL_TOKEN_BRIDGE_ADDRESS =
CLUSTER === "mainnet"
? "wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb"
: CLUSTER === "testnet"
- ? "A4Us8EhCC76XdGAN17L4KpRNEK423nMivVHZzZqFqqBg"
+ ? "GQemgcTaC6jojXS4pH4YPDD72b6RPsDhNPSjmxMfYcet"
: "B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE";
export const SOL_CUSTODY_ADDRESS =
@@ -272,13 +270,13 @@ export const TERRA_BRIDGE_ADDRESS =
CLUSTER === "mainnet"
? "terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5"
: CLUSTER === "testnet"
- ? "terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5"
+ ? "terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v"
: "terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5";
export const TERRA_TOKEN_BRIDGE_ADDRESS =
CLUSTER === "mainnet"
? "terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf"
: CLUSTER === "testnet"
- ? "terra10pyejy66429refv3g35g2t7am0was7ya7kz2a4"
+ ? "terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a"
: "terra10pyejy66429refv3g35g2t7am0was7ya7kz2a4";
export const getBridgeAddressForChain = (chainId: ChainId) =>
@@ -666,3 +664,5 @@ export const AVAILABLE_MARKETS_URL =
"https://docs.wormholenetwork.com/wormhole/overview-liquid-markets";
export const SOLANA_SYSTEM_PROGRAM_ADDRESS = "11111111111111111111111111111111";
+export const FEATURED_MARKETS_JSON_URL =
+ "https://raw.githubusercontent.com/certusone/wormhole-token-list/main/src/markets.json";