bridge_ui: prep polygon support

Change-Id: I6bd45eb0ce6b7f97ba78e8569fa05f9f027be0d5
This commit is contained in:
Evan Gray 2021-10-26 17:02:53 -04:00
parent 1ccd9eef12
commit ad33cac284
12 changed files with 190 additions and 15 deletions

View File

@ -1,6 +1,7 @@
import {
CHAIN_ID_BSC,
CHAIN_ID_ETH,
CHAIN_ID_POLYGON,
CHAIN_ID_SOLANA,
hexToNativeString,
uint8ArrayToHex,
@ -316,6 +317,17 @@ export default function NFTOriginVerifier() {
>
View on BscScan
</Button>
) : originInfo.chainId === CHAIN_ID_POLYGON ? (
<Button
href={`https://opensea.io/assets/matic/${readableAddress}/${originInfo.tokenId}`}
target="_blank"
rel="noopener noreferrer"
endIcon={<Launch />}
className={classes.viewButton}
variant="outlined"
>
View on OpenSea
</Button>
) : (
<Button
href={`https://opensea.io/assets/${readableAddress}/${originInfo.tokenId}`}

View File

@ -2,6 +2,7 @@ import {
ChainId,
CHAIN_ID_BSC,
CHAIN_ID_ETH,
CHAIN_ID_POLYGON,
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
} from "@certusone/wormhole-sdk";
@ -39,6 +40,8 @@ export default function ShowTx({
}`
: chainId === CHAIN_ID_BSC
? `https://bscscan.com/tx/${tx?.id}`
: chainId === CHAIN_ID_POLYGON
? `https://polygonscan.com/tx/${tx?.id}`
: chainId === CHAIN_ID_SOLANA
? `https://explorer.solana.com/tx/${tx?.id}${
CLUSTER === "testnet"

View File

@ -2,6 +2,7 @@ import {
ChainId,
CHAIN_ID_BSC,
CHAIN_ID_ETH,
CHAIN_ID_POLYGON,
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
isNativeDenom,
@ -98,6 +99,8 @@ export default function SmartAddress({
}etherscan.io/address/${useableAddress}`
: chainId === CHAIN_ID_BSC
? `https://bscscan.com/address/${useableAddress}`
: chainId === CHAIN_ID_POLYGON
? `https://polygonscan.com/address/${useableAddress}`
: chainId === CHAIN_ID_SOLANA
? `https://explorer.solana.com/address/${useableAddress}${
CLUSTER === "testnet"

View File

@ -15,12 +15,14 @@ import {
ChainId,
CHAIN_ID_BSC,
CHAIN_ID_ETH,
CHAIN_ID_POLYGON,
CHAIN_ID_SOLANA,
} from "@certusone/wormhole-sdk";
import SmartAddress from "../SmartAddress";
import bscIcon from "../../icons/bsc.svg";
import ethIcon from "../../icons/eth.svg";
import solanaIcon from "../../icons/solana.svg";
import polygonIcon from "../../icons/polygon.svg";
import useCopyToClipboard from "../../hooks/useCopyToClipboard";
import { Skeleton } from "@material-ui/lab";
import Wormhole from "../../icons/wormhole-network.svg";
@ -69,6 +71,18 @@ const LogoIcon = ({ chainId }: { chainId: ChainId }) =>
src={bscIcon}
alt="Binance Smart Chain"
/>
) : chainId === CHAIN_ID_POLYGON ? (
<Avatar
style={{
backgroundColor: "black",
height: "1em",
width: "1em",
marginLeft: "4px",
padding: "3px",
}}
src={polygonIcon}
alt="Polygon"
/>
) : null;
const useStyles = makeStyles((theme) => ({
@ -90,7 +104,7 @@ const useStyles = makeStyles((theme) => ({
background:
"linear-gradient(to right, #ffb347 0%, #ffcc33 51%, #ffb347 100%)",
},
solanaBorder: {
silverBorder: {
backgroundColor: "#D9D8D6",
backgroundSize: "200% auto",
background:
@ -135,12 +149,12 @@ const useStyles = makeStyles((theme) => ({
border: "1px solid #ffb347",
},
},
solanaMediaBorder: {
silverMediaBorder: {
"& > img, & > video": {
borderColor: "#D7DDE8",
},
},
// thanks https://cssgradient.io/
// thanks https://cssgradient.io/ and https://htmlcolorcodes.com/color-picker/
eth: {
// colors from https://en.wikipedia.org/wiki/Ethereum#/media/File:Ethereum-icon-purple.svg
backgroundColor: "rgb(69,74,117)",
@ -153,6 +167,12 @@ const useStyles = makeStyles((theme) => ({
background:
"linear-gradient(160deg, rgb(20, 21, 26) 0%, #4A4D57 33%, rgb(20, 21, 26) 66%, #2C2F3B 100%)",
},
polygon: {
// color from polygon logo #8247E5 down to 30 lightness
backgroundColor: "#0F0323",
background:
"linear-gradient(160deg, #0F0323 0%, #250957 33%, #0F0323 66%, #0F0323 100%)",
},
solana: {
// colors from https://solana.com/branding/new/exchange/exchange-sq-black.svg
backgroundColor: "rgb(153,69,255)",
@ -354,7 +374,8 @@ export default function NFTViewer({
</div>
<Card
className={clsx(classes.card, {
[classes.solanaBorder]: chainId === CHAIN_ID_SOLANA,
[classes.silverBorder]:
chainId === CHAIN_ID_SOLANA || chainId === CHAIN_ID_POLYGON,
[classes.hidden]: isLoading,
})}
elevation={10}
@ -364,6 +385,7 @@ export default function NFTViewer({
[classes.eth]: chainId === CHAIN_ID_ETH,
[classes.bsc]: chainId === CHAIN_ID_BSC,
[classes.solana]: chainId === CHAIN_ID_SOLANA,
[classes.polygon]: chainId === CHAIN_ID_POLYGON,
})}
>
<CardContent className={classes.textContent}>
@ -384,7 +406,8 @@ export default function NFTViewer({
</CardContent>
<CardMedia
className={clsx(classes.mediaContent, {
[classes.solanaMediaBorder]: chainId === CHAIN_ID_SOLANA,
[classes.silverMediaBorder]:
chainId === CHAIN_ID_SOLANA || chainId === CHAIN_ID_POLYGON,
})}
>
{media}

View File

@ -1,6 +1,7 @@
import {
CHAIN_ID_BSC,
CHAIN_ID_ETH,
CHAIN_ID_POLYGON,
CHAIN_ID_SOLANA,
WSOL_ADDRESS,
} from "@certusone/wormhole-sdk";
@ -13,7 +14,7 @@ import {
selectTransferTargetAsset,
selectTransferTargetChain,
} from "../../store/selectors";
import { WBNB_ADDRESS, WETH_ADDRESS } from "../../utils/consts";
import { WBNB_ADDRESS, WETH_ADDRESS, WMATIC_ADDRESS } from "../../utils/consts";
import ButtonWithLoader from "../ButtonWithLoader";
import KeyAndBalance from "../KeyAndBalance";
import { SolanaCreateAssociatedAddressAlternate } from "../SolanaCreateAssociatedAddress";
@ -35,11 +36,16 @@ function Redeem() {
targetChain === CHAIN_ID_BSC &&
targetAsset &&
targetAsset.toLowerCase() === WBNB_ADDRESS.toLowerCase();
const isPolygonNative =
targetChain === CHAIN_ID_POLYGON &&
targetAsset &&
targetAsset.toLowerCase() === WMATIC_ADDRESS.toLowerCase();
const isSolNative =
targetChain === CHAIN_ID_SOLANA &&
targetAsset &&
targetAsset === WSOL_ADDRESS;
const isNativeEligible = isEthNative || isBscNative || isSolNative;
const isNativeEligible =
isEthNative || isBscNative || isPolygonNative || isSolNative;
const [useNativeRedeem, setUseNativeRedeem] = useState(true);
const toggleNativeRedeem = useCallback(() => {
setUseNativeRedeem(!useNativeRedeem);

View File

@ -2,6 +2,7 @@ import {
ChainId,
CHAIN_ID_BSC,
CHAIN_ID_ETH,
CHAIN_ID_POLYGON,
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
WSOL_ADDRESS,
@ -59,6 +60,8 @@ import {
WBNB_DECIMALS,
WETH_ADDRESS,
WETH_DECIMALS,
WMATIC_ADDRESS,
WMATIC_DECIMALS,
} from "../utils/consts";
import { isEVMChain } from "../utils/ethereum";
import {
@ -68,6 +71,7 @@ import {
} from "../utils/solana";
import bnbIcon from "../icons/bnb.svg";
import ethIcon from "../icons/eth.svg";
import polygonIcon from "../icons/polygon.svg";
export function createParsedTokenAccount(
publicKey: string,
@ -207,7 +211,7 @@ const createNativeEthParsedTokenAccount = (
balanceInEth.toString(), //This is the actual display field, which has full precision.
"ETH", //A white lie for display purposes
"Ethereum", //A white lie for display purposes
ethIcon, //TODO logo
ethIcon,
true //isNativeAsset
);
});
@ -230,7 +234,30 @@ const createNativeBscParsedTokenAccount = (
balanceInEth.toString(), //This is the actual display field, which has full precision.
"BNB", //A white lie for display purposes
"Binance Coin", //A white lie for display purposes
bnbIcon, //TODO logo
bnbIcon,
true //isNativeAsset
);
});
};
const createNativePolygonParsedTokenAccount = (
provider: Provider,
signerAddress: string | undefined
) => {
return !(provider && signerAddress)
? Promise.reject()
: provider.getBalance(signerAddress).then((balanceInWei) => {
const balanceInEth = ethers.utils.formatEther(balanceInWei);
return createParsedTokenAccount(
signerAddress, //public key
WMATIC_ADDRESS, //Mint key, On the other side this will be WMATIC, so this is hopefully a white lie.
balanceInWei.toString(), //amount, in wei
WMATIC_DECIMALS, //Luckily both MATIC and WMATIC have 18 decimals, so this should not be an issue.
parseFloat(balanceInEth), //This loses precision, but is a limitation of the current datamodel. This field is essentially deprecated
balanceInEth.toString(), //This is the actual display field, which has full precision.
"MATIC", //A white lie for display purposes
"Matic", //A white lie for display purposes
polygonIcon,
true //isNativeAsset
);
});
@ -604,7 +631,41 @@ function useGetAvailableTokens(nft: boolean = false) {
if (!cancelled) {
setEthNativeAccount(undefined);
setEthNativeAccountLoading(false);
setEthNativeAccountError("Unable to retrieve your BSC balance.");
setEthNativeAccountError("Unable to retrieve your BNB balance.");
}
}
);
}
return () => {
cancelled = true;
};
}, [lookupChain, provider, signerAddress, nft, ethNativeAccount]);
//Polygon native asset load
useEffect(() => {
let cancelled = false;
if (
signerAddress &&
lookupChain === CHAIN_ID_POLYGON &&
!ethNativeAccount &&
!nft
) {
setEthNativeAccountLoading(true);
createNativePolygonParsedTokenAccount(provider, signerAddress).then(
(result) => {
console.log("create native account returned with value", result);
if (!cancelled) {
setEthNativeAccount(result);
setEthNativeAccountLoading(false);
setEthNativeAccountError("");
}
},
(error) => {
if (!cancelled) {
setEthNativeAccount(undefined);
setEthNativeAccountLoading(false);
setEthNativeAccountError("Unable to retrieve your MATIC balance.");
}
}
);

View File

@ -2,6 +2,7 @@ import {
ChainId,
CHAIN_ID_BSC,
CHAIN_ID_ETH,
CHAIN_ID_POLYGON,
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
} from "@certusone/wormhole-sdk";
@ -9,6 +10,7 @@ import { clusterApiUrl } from "@solana/web3.js";
import { getAddress } from "ethers/lib/utils";
import bscIcon from "../icons/bsc.svg";
import ethIcon from "../icons/eth.svg";
// import polygonIcon from "../icons/polygon.svg";
import solanaIcon from "../icons/solana.svg";
import terraIcon from "../icons/terra.svg";
@ -37,6 +39,11 @@ export const CHAINS =
name: "Ethereum",
logo: ethIcon,
},
// {
// id: CHAIN_ID_POLYGON,
// name: "Polygon",
// logo: polygonIcon,
// },
{
id: CHAIN_ID_SOLANA,
name: "Solana",
@ -86,7 +93,10 @@ export const CHAINS =
export const BETA_CHAINS: ChainId[] = CLUSTER === "mainnet" ? [] : [];
export const CHAINS_WITH_NFT_SUPPORT = CHAINS.filter(
({ id }) =>
id === CHAIN_ID_ETH || id === CHAIN_ID_BSC || id === CHAIN_ID_SOLANA
id === CHAIN_ID_BSC ||
id === CHAIN_ID_ETH ||
id === CHAIN_ID_POLYGON ||
id === CHAIN_ID_SOLANA
);
export type ChainsById = { [key in ChainId]: ChainInfo };
export const CHAINS_BY_ID: ChainsById = CHAINS.reduce((obj, chain) => {
@ -102,6 +112,8 @@ export const getDefaultNativeCurrencySymbol = (chainId: ChainId) =>
? "BNB"
: chainId === CHAIN_ID_TERRA
? "LUNA"
: chainId === CHAIN_ID_POLYGON
? "MATIC"
: "";
export const getExplorerName = (chainId: ChainId) =>
chainId === CHAIN_ID_ETH
@ -110,6 +122,8 @@ export const getExplorerName = (chainId: ChainId) =>
? "BscScan"
: chainId === CHAIN_ID_TERRA
? "Finder"
: chainId === CHAIN_ID_POLYGON
? "Polygonscan"
: "Explorer";
export const WORMHOLE_RPC_HOSTS =
CLUSTER === "mainnet"
@ -130,11 +144,15 @@ export const ETH_NETWORK_CHAIN_ID =
CLUSTER === "mainnet" ? 1 : CLUSTER === "testnet" ? 5 : 1337;
export const BSC_NETWORK_CHAIN_ID =
CLUSTER === "mainnet" ? 56 : CLUSTER === "testnet" ? 97 : 1397;
export const POLYGON_NETWORK_CHAIN_ID =
CLUSTER === "mainnet" ? 137 : CLUSTER === "testnet" ? 80001 : 1381;
export const getEvmChainId = (chainId: ChainId) =>
chainId === CHAIN_ID_ETH
? ETH_NETWORK_CHAIN_ID
: chainId === CHAIN_ID_BSC
? BSC_NETWORK_CHAIN_ID
: chainId === CHAIN_ID_POLYGON
? POLYGON_NETWORK_CHAIN_ID
: undefined;
export const SOLANA_HOST = process.env.REACT_APP_SOLANA_API_URL
? process.env.REACT_APP_SOLANA_API_URL
@ -204,6 +222,27 @@ export const BSC_TOKEN_BRIDGE_ADDRESS = getAddress(
? "0x0290FB167208Af455bB137780163b7B7a9a10C16" // TODO: test address
: "0x0290FB167208Af455bB137780163b7B7a9a10C16"
);
export const POLYGON_BRIDGE_ADDRESS = getAddress(
CLUSTER === "mainnet"
? "0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7"
: CLUSTER === "testnet"
? "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550" // TODO: test address
: "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
);
export const POLYGON_NFT_BRIDGE_ADDRESS = getAddress(
CLUSTER === "mainnet"
? "0x90BBd86a6Fe93D3bc3ed6335935447E75fAb7fCf"
: CLUSTER === "testnet"
? "0x26b4afb60d6c903165150c6f0aa14f8016be4aec" // TODO: test address
: "0x26b4afb60d6c903165150c6f0aa14f8016be4aec"
);
export const POLYGON_TOKEN_BRIDGE_ADDRESS = getAddress(
CLUSTER === "mainnet"
? "0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE"
: CLUSTER === "testnet"
? "0x0290FB167208Af455bB137780163b7B7a9a10C16" // TODO: test address
: "0x0290FB167208Af455bB137780163b7B7a9a10C16"
);
export const SOL_BRIDGE_ADDRESS =
CLUSTER === "mainnet"
? "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth"
@ -251,6 +290,8 @@ export const getBridgeAddressForChain = (chainId: ChainId) =>
? BSC_BRIDGE_ADDRESS
: chainId === CHAIN_ID_TERRA
? TERRA_BRIDGE_ADDRESS
: chainId === CHAIN_ID_POLYGON
? POLYGON_BRIDGE_ADDRESS
: "";
export const getNFTBridgeAddressForChain = (chainId: ChainId) =>
chainId === CHAIN_ID_SOLANA
@ -259,6 +300,8 @@ export const getNFTBridgeAddressForChain = (chainId: ChainId) =>
? ETH_NFT_BRIDGE_ADDRESS
: chainId === CHAIN_ID_BSC
? BSC_NFT_BRIDGE_ADDRESS
: chainId === CHAIN_ID_POLYGON
? POLYGON_NFT_BRIDGE_ADDRESS
: "";
export const getTokenBridgeAddressForChain = (chainId: ChainId) =>
chainId === CHAIN_ID_SOLANA
@ -269,6 +312,8 @@ export const getTokenBridgeAddressForChain = (chainId: ChainId) =>
? BSC_TOKEN_BRIDGE_ADDRESS
: chainId === CHAIN_ID_TERRA
? TERRA_TOKEN_BRIDGE_ADDRESS
: chainId === CHAIN_ID_POLYGON
? POLYGON_TOKEN_BRIDGE_ADDRESS
: "";
export const COVALENT_API_KEY = process.env.REACT_APP_COVALENT_API_KEY
@ -277,6 +322,7 @@ export const COVALENT_API_KEY = process.env.REACT_APP_COVALENT_API_KEY
export const COVALENT_ETHEREUM_MAINNET = "1";
export const COVALENT_BSC_MAINNET = "56";
export const COVALENT_POLYGON_MAINNET = "137";
export const COVALENT_GET_TOKENS_URL = (
chainId: ChainId,
walletAddress: string,
@ -288,6 +334,8 @@ export const COVALENT_GET_TOKENS_URL = (
? COVALENT_ETHEREUM_MAINNET
: chainId === CHAIN_ID_BSC
? COVALENT_BSC_MAINNET
: chainId === CHAIN_ID_POLYGON
? COVALENT_POLYGON_MAINNET
: "";
// https://www.covalenthq.com/docs/api/#get-/v1/{chain_id}/address/{address}/balances_v2/
return `https://api.covalenthq.com/v1/${chainNum}/address/${walletAddress}/balances_v2/?key=${COVALENT_API_KEY}${
@ -313,6 +361,14 @@ export const WBNB_ADDRESS =
: "0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E";
export const WBNB_DECIMALS = 18;
export const WMATIC_ADDRESS =
CLUSTER === "mainnet"
? "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270"
: CLUSTER === "testnet"
? ""
: "0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E";
export const WMATIC_DECIMALS = 18;
export const WORMHOLE_V1_ETH_ADDRESS =
CLUSTER === "mainnet"
? "0xf92cD566Ea4864356C5491c177A430C222d7e678"

View File

@ -2,6 +2,7 @@ import {
ChainId,
CHAIN_ID_BSC,
CHAIN_ID_ETH,
CHAIN_ID_POLYGON,
NFTImplementation,
NFTImplementation__factory,
TokenImplementation,
@ -15,7 +16,9 @@ import {
} from "../hooks/useGetSourceParsedTokenAccounts";
export const isEVMChain = (chainId: ChainId) =>
chainId === CHAIN_ID_ETH || chainId === CHAIN_ID_BSC;
chainId === CHAIN_ID_ETH ||
chainId === CHAIN_ID_BSC ||
chainId === CHAIN_ID_POLYGON;
//This is a valuable intermediate step to the parsed token account, as the token has metadata information on it.
export async function getEthereumToken(

View File

@ -1,5 +1,11 @@
# Changelog
## 0.0.8
### Added
Polygon ChainId
## 0.0.7
### Changed

View File

@ -1,6 +1,6 @@
{
"name": "@certusone/wormhole-sdk",
"version": "0.0.7",
"version": "0.0.8",
"description": "SDK for interacting with Wormhole",
"homepage": "https://wormholenetwork.com",
"main": "lib/index.js",

View File

@ -4,6 +4,7 @@ import {
CHAIN_ID_ETH,
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
CHAIN_ID_POLYGON,
} from "./consts";
import { humanAddress } from "../terra";
import { PublicKey } from "@solana/web3.js";
@ -22,7 +23,7 @@ export const hexToNativeString = (h: string | undefined, c: ChainId) => {
? undefined
: c === CHAIN_ID_SOLANA
? new PublicKey(hexToUint8Array(h)).toString()
: c === CHAIN_ID_ETH || c === CHAIN_ID_BSC
: c === CHAIN_ID_ETH || c === CHAIN_ID_BSC || c === CHAIN_ID_POLYGON
? hexZeroPad(hexValue(hexToUint8Array(h)), 20)
: c === CHAIN_ID_TERRA
? isHexNativeTerra(h)

View File

@ -1,8 +1,9 @@
export type ChainId = 1 | 2 | 3 | 4;
export type ChainId = 1 | 2 | 3 | 4 | 5;
export const CHAIN_ID_SOLANA: ChainId = 1;
export const CHAIN_ID_ETH: ChainId = 2;
export const CHAIN_ID_TERRA: ChainId = 3;
export const CHAIN_ID_BSC: ChainId = 4;
export const CHAIN_ID_POLYGON: ChainId = 5;
export const WSOL_ADDRESS = "So11111111111111111111111111111111111111112";
export const WSOL_DECIMALS = 9;