فهرست منبع

bridge_ui: oasis support

Chase Moran 3 سال پیش
والد
کامیت
195a61714e

+ 8 - 8
bridge_ui/package-lock.json

@@ -8,7 +8,7 @@
       "name": "test_ui",
       "version": "0.1.0",
       "dependencies": {
-        "@certusone/wormhole-sdk": "^0.1.4",
+        "@certusone/wormhole-sdk": "^0.1.5",
         "@material-ui/core": "^4.12.2",
         "@material-ui/icons": "^4.11.2",
         "@material-ui/lab": "^4.0.0-alpha.60",
@@ -63,7 +63,7 @@
     },
     "../sdk/js": {
       "name": "@certusone/wormhole-sdk",
-      "version": "0.1.3",
+      "version": "0.1.5",
       "extraneous": true,
       "license": "Apache-2.0",
       "dependencies": {
@@ -2002,9 +2002,9 @@
       }
     },
     "node_modules/@certusone/wormhole-sdk": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.1.4.tgz",
-      "integrity": "sha512-C9GXZJ3vjBDU1Ytk6Sk5SYS3oJFjUa7vEq1NlOwHCwt5CL0vFwdrBq3WER8h1+i+/4AaGreOyCpxct0tXeasXg==",
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.1.5.tgz",
+      "integrity": "sha512-xRRItdrIDNVA4S4krmkq2JwNCpkcqAjbTRhPGNLKx29v2TSiOZ3MEug31urPvdfcvPM7DerN+o0LnGy9LMmboA==",
       "dependencies": {
         "@improbable-eng/grpc-web": "^0.14.0",
         "@solana/spl-token": "^0.1.8",
@@ -45479,9 +45479,9 @@
       }
     },
     "@certusone/wormhole-sdk": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.1.4.tgz",
-      "integrity": "sha512-C9GXZJ3vjBDU1Ytk6Sk5SYS3oJFjUa7vEq1NlOwHCwt5CL0vFwdrBq3WER8h1+i+/4AaGreOyCpxct0tXeasXg==",
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.1.5.tgz",
+      "integrity": "sha512-xRRItdrIDNVA4S4krmkq2JwNCpkcqAjbTRhPGNLKx29v2TSiOZ3MEug31urPvdfcvPM7DerN+o0LnGy9LMmboA==",
       "requires": {
         "@improbable-eng/grpc-web": "^0.14.0",
         "@solana/spl-token": "^0.1.8",

+ 1 - 1
bridge_ui/package.json

@@ -3,7 +3,7 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
-    "@certusone/wormhole-sdk": "^0.1.4",
+    "@certusone/wormhole-sdk": "^0.1.5",
     "@material-ui/core": "^4.12.2",
     "@material-ui/icons": "^4.11.2",
     "@material-ui/lab": "^4.0.0-alpha.60",

+ 2 - 1
bridge_ui/src/components/NFTOriginVerifier.tsx

@@ -4,6 +4,7 @@ import {
   CHAIN_ID_ETH,
   CHAIN_ID_POLYGON,
   CHAIN_ID_SOLANA,
+  CHAIN_ID_OASIS,
   hexToNativeString,
   isEVMChain,
   uint8ArrayToHex,
@@ -342,7 +343,7 @@ export default function NFTOriginVerifier() {
                   >
                     View on Snowtrace
                   </Button>
-                ) : (
+                ) : originInfo.chainId === CHAIN_ID_OASIS ? null : (
                   <Button
                     href={`https://opensea.io/assets/${readableAddress}/${originInfo.tokenId}`}
                     target="_blank"

+ 3 - 0
bridge_ui/src/components/ShowTx.tsx

@@ -7,6 +7,7 @@ import {
   CHAIN_ID_POLYGON,
   CHAIN_ID_SOLANA,
   CHAIN_ID_TERRA,
+  CHAIN_ID_OASIS,
 } from "@certusone/wormhole-sdk";
 import { Button, makeStyles, Typography } from "@material-ui/core";
 import { Transaction } from "../store/transferSlice";
@@ -56,6 +57,8 @@ export default function ShowTx({
       ? `https://${CLUSTER === "testnet" ? "testnet." : ""}snowtrace.io/tx/${
           tx?.id
         }`
+      : chainId === CHAIN_ID_OASIS
+      ? undefined
       : chainId === CHAIN_ID_SOLANA
       ? `https://explorer.solana.com/tx/${tx?.id}${
           CLUSTER === "testnet"

+ 3 - 0
bridge_ui/src/components/SmartAddress.tsx

@@ -7,6 +7,7 @@ import {
   CHAIN_ID_POLYGON,
   CHAIN_ID_SOLANA,
   CHAIN_ID_TERRA,
+  CHAIN_ID_OASIS,
   isNativeDenom,
 } from "@certusone/wormhole-sdk";
 import { Button, makeStyles, Tooltip, Typography } from "@material-ui/core";
@@ -115,6 +116,8 @@ export default function SmartAddress({
     ? `https://${
         CLUSTER === "testnet" ? "testnet." : ""
       }snowtrace.io/address/${useableAddress}`
+    : chainId === CHAIN_ID_OASIS
+    ? null
     : chainId === CHAIN_ID_SOLANA
     ? `https://explorer.solana.com/address/${useableAddress}${
         CLUSTER === "testnet"

+ 17 - 1
bridge_ui/src/components/TokenSelectors/NFTViewer.tsx

@@ -19,6 +19,7 @@ import {
   CHAIN_ID_ETHEREUM_ROPSTEN,
   CHAIN_ID_POLYGON,
   CHAIN_ID_SOLANA,
+  CHAIN_ID_OASIS,
 } from "@certusone/wormhole-sdk";
 import SmartAddress from "../SmartAddress";
 import avaxIcon from "../../icons/avax.svg";
@@ -26,6 +27,7 @@ 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 oasisIcon from "../../icons/oasis-network-rose-logo.svg";
 import useCopyToClipboard from "../../hooks/useCopyToClipboard";
 import { Skeleton } from "@material-ui/lab";
 import Wormhole from "../../icons/wormhole-network.svg";
@@ -99,6 +101,18 @@ const LogoIcon = ({ chainId }: { chainId: ChainId }) =>
       src={avaxIcon}
       alt="Avalanche"
     />
+  ) : chainId === CHAIN_ID_OASIS ? (
+    <Avatar
+      style={{
+        backgroundColor: "black",
+        height: "1em",
+        width: "1em",
+        marginLeft: "4px",
+        padding: "3px",
+      }}
+      src={oasisIcon}
+      alt="Oasis"
+    />
   ) : null;
 
 const useStyles = makeStyles((theme) => ({
@@ -400,7 +414,8 @@ export default function NFTViewer({
             [classes.eth]:
               chainId === CHAIN_ID_ETH ||
               chainId === CHAIN_ID_ETHEREUM_ROPSTEN ||
-              chainId === CHAIN_ID_AVAX, //TODO: give avax it's own bg
+              chainId === CHAIN_ID_AVAX || //TODO: give avax it's own bg
+              chainId === CHAIN_ID_OASIS, //TODO: give oasis it's own bg
             [classes.bsc]: chainId === CHAIN_ID_BSC,
             [classes.solana]: chainId === CHAIN_ID_SOLANA,
             [classes.polygon]: chainId === CHAIN_ID_POLYGON,
@@ -427,6 +442,7 @@ export default function NFTViewer({
               [classes.silverMediaBorder]:
                 chainId === CHAIN_ID_SOLANA ||
                 chainId === CHAIN_ID_POLYGON ||
+                chainId === CHAIN_ID_OASIS ||
                 chainId === CHAIN_ID_AVAX,
             })}
           >

+ 7 - 0
bridge_ui/src/components/Transfer/Redeem.tsx

@@ -3,6 +3,7 @@ import {
   CHAIN_ID_BSC,
   CHAIN_ID_ETH,
   CHAIN_ID_ETHEREUM_ROPSTEN,
+  CHAIN_ID_OASIS,
   CHAIN_ID_POLYGON,
   CHAIN_ID_SOLANA,
   isEVMChain,
@@ -37,6 +38,7 @@ import {
   WBNB_ADDRESS,
   WETH_ADDRESS,
   WMATIC_ADDRESS,
+  WROSE_ADDRESS,
 } from "../../utils/consts";
 import ButtonWithLoader from "../ButtonWithLoader";
 import KeyAndBalance from "../KeyAndBalance";
@@ -91,6 +93,10 @@ function Redeem() {
     targetChain === CHAIN_ID_AVAX &&
     targetAsset &&
     targetAsset.toLowerCase() === WAVAX_ADDRESS.toLowerCase();
+  const isOasisNative =
+    targetChain === CHAIN_ID_OASIS &&
+    targetAsset &&
+    targetAsset.toLowerCase() === WROSE_ADDRESS.toLowerCase();
   const isSolNative =
     targetChain === CHAIN_ID_SOLANA &&
     targetAsset &&
@@ -101,6 +107,7 @@ function Redeem() {
     isBscNative ||
     isPolygonNative ||
     isAvaxNative ||
+    isOasisNative ||
     isSolNative;
   const [useNativeRedeem, setUseNativeRedeem] = useState(true);
   const toggleNativeRedeem = useCallback(() => {

+ 60 - 0
bridge_ui/src/hooks/useGetSourceParsedTokenAccounts.ts

@@ -7,6 +7,7 @@ import {
   CHAIN_ID_POLYGON,
   CHAIN_ID_SOLANA,
   CHAIN_ID_TERRA,
+  CHAIN_ID_OASIS,
   isEVMChain,
   WSOL_ADDRESS,
   WSOL_DECIMALS,
@@ -70,6 +71,8 @@ import {
   WETH_DECIMALS,
   WMATIC_ADDRESS,
   WMATIC_DECIMALS,
+  WROSE_ADDRESS,
+  WROSE_DECIMALS,
 } from "../utils/consts";
 import {
   ExtractedMintInfo,
@@ -80,6 +83,7 @@ import avaxIcon from "../icons/avax.svg";
 import bnbIcon from "../icons/bnb.svg";
 import ethIcon from "../icons/eth.svg";
 import polygonIcon from "../icons/polygon.svg";
+import oasisIcon from "../icons/oasis-network-rose-logo.svg";
 
 export function createParsedTokenAccount(
   publicKey: string,
@@ -317,6 +321,29 @@ const createNativeAvaxParsedTokenAccount = (
       });
 };
 
+const createNativeOasisParsedTokenAccount = (
+  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
+          WROSE_ADDRESS, //Mint key, On the other side this will be wavax, so this is hopefully a white lie.
+          balanceInWei.toString(), //amount, in wei
+          WROSE_DECIMALS,
+          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.
+          "ROSE", //A white lie for display purposes
+          "Rose", //A white lie for display purposes
+          oasisIcon,
+          true //isNativeAsset
+        );
+      });
+};
+
 const createNFTParsedTokenAccountFromCovalent = (
   walletAddress: string,
   covalent: CovalentData,
@@ -799,6 +826,39 @@ function useGetAvailableTokens(nft: boolean = false) {
     };
   }, [lookupChain, provider, signerAddress, nft, ethNativeAccount]);
 
+  useEffect(() => {
+    let cancelled = false;
+    if (
+      signerAddress &&
+      lookupChain === CHAIN_ID_OASIS &&
+      !ethNativeAccount &&
+      !nft
+    ) {
+      setEthNativeAccountLoading(true);
+      createNativeOasisParsedTokenAccount(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 Oasis balance.");
+          }
+        }
+      );
+    }
+
+    return () => {
+      cancelled = true;
+    };
+  }, [lookupChain, provider, signerAddress, nft, ethNativeAccount]);
+
   //Ethereum covalent accounts load
   useEffect(() => {
     //const testWallet = "0xf60c2ea62edbfe808163751dd0d8693dcb30019c";

+ 59 - 3
bridge_ui/src/utils/consts.ts

@@ -7,6 +7,7 @@ import {
   CHAIN_ID_POLYGON,
   CHAIN_ID_SOLANA,
   CHAIN_ID_TERRA,
+  CHAIN_ID_OASIS,
   isEVMChain,
 } from "@certusone/wormhole-sdk";
 import { clusterApiUrl } from "@solana/web3.js";
@@ -39,6 +40,11 @@ export const CHAINS =
           name: "Avalanche",
           logo: avaxIcon,
         },
+        {
+          id: CHAIN_ID_OASIS,
+          name: "Oasis",
+          logo: oasisIcon,
+        },
         {
           id: CHAIN_ID_BSC,
           name: "Binance Smart Chain",
@@ -72,6 +78,11 @@ export const CHAINS =
           name: "Avalanche",
           logo: avaxIcon,
         },
+        {
+          id: CHAIN_ID_OASIS,
+          name: "Oasis",
+          logo: oasisIcon,
+        },
         {
           id: CHAIN_ID_BSC,
           name: "Binance Smart Chain",
@@ -126,7 +137,7 @@ export const CHAINS =
         },
       ];
 export const BETA_CHAINS: ChainId[] =
-  CLUSTER === "mainnet" ? [CHAIN_ID_AVAX] : [];
+  CLUSTER === "mainnet" ? [CHAIN_ID_AVAX, CHAIN_ID_OASIS] : [];
 export const CHAINS_WITH_NFT_SUPPORT = CHAINS.filter(
   ({ id }) =>
     id === CHAIN_ID_AVAX ||
@@ -134,6 +145,7 @@ export const CHAINS_WITH_NFT_SUPPORT = CHAINS.filter(
     id === CHAIN_ID_ETH ||
     id === CHAIN_ID_ETHEREUM_ROPSTEN ||
     id === CHAIN_ID_POLYGON ||
+    id === CHAIN_ID_OASIS ||
     id === CHAIN_ID_SOLANA
 );
 export type ChainsById = { [key in ChainId]: ChainInfo };
@@ -144,12 +156,12 @@ export const CHAINS_BY_ID: ChainsById = CHAINS.reduce((obj, chain) => {
 
 export const COMING_SOON_CHAINS = [
   {
-    id: 0,
+    id: CHAIN_ID_OASIS,
     name: "Oasis",
     logo: oasisIcon,
   },
   {
-    id: 0,
+    id: CHAIN_ID_AVAX,
     name: "Avalanche",
     logo: avaxIcon,
   },
@@ -167,6 +179,8 @@ export const getDefaultNativeCurrencySymbol = (chainId: ChainId) =>
     ? "MATIC"
     : chainId === CHAIN_ID_AVAX
     ? "AVAX"
+    : chainId === CHAIN_ID_OASIS
+    ? "ROSE"
     : "";
 export const getExplorerName = (chainId: ChainId) =>
   chainId === CHAIN_ID_ETH || chainId === CHAIN_ID_ETHEREUM_ROPSTEN
@@ -203,6 +217,8 @@ export const POLYGON_NETWORK_CHAIN_ID =
   CLUSTER === "mainnet" ? 137 : CLUSTER === "testnet" ? 80001 : 1381;
 export const AVAX_NETWORK_CHAIN_ID =
   CLUSTER === "mainnet" ? 43114 : CLUSTER === "testnet" ? 43113 : 1381;
+export const OASIS_NETWORK_CHAIN_ID =
+  CLUSTER === "mainnet" ? 42262 : CLUSTER === "testnet" ? 42261 : 1381;
 export const getEvmChainId = (chainId: ChainId) =>
   chainId === CHAIN_ID_ETH
     ? ETH_NETWORK_CHAIN_ID
@@ -214,6 +230,8 @@ export const getEvmChainId = (chainId: ChainId) =>
     ? POLYGON_NETWORK_CHAIN_ID
     : chainId === CHAIN_ID_AVAX
     ? AVAX_NETWORK_CHAIN_ID
+    : chainId === CHAIN_ID_OASIS
+    ? OASIS_NETWORK_CHAIN_ID
     : undefined;
 export const SOLANA_HOST = process.env.REACT_APP_SOLANA_API_URL
   ? process.env.REACT_APP_SOLANA_API_URL
@@ -325,6 +343,27 @@ export const AVAX_TOKEN_BRIDGE_ADDRESS = getAddress(
     ? "0x61E44E506Ca5659E6c0bba9b678586fA2d729756"
     : "0x0290FB167208Af455bB137780163b7B7a9a10C16"
 );
+export const OASIS_BRIDGE_ADDRESS = getAddress(
+  CLUSTER === "mainnet"
+    ? "0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585"
+    : CLUSTER === "testnet"
+    ? "0xc1C338397ffA53a2Eb12A7038b4eeb34791F8aCb"
+    : "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
+);
+export const OASIS_NFT_BRIDGE_ADDRESS = getAddress(
+  CLUSTER === "mainnet"
+    ? "0x04952D522Ff217f40B5Ef3cbF659EcA7b952a6c1"
+    : CLUSTER === "testnet"
+    ? "0xC5c25B41AB0b797571620F5204Afa116A44c0ebA"
+    : "0x26b4afb60d6c903165150c6f0aa14f8016be4aec"
+);
+export const OASIS_TOKEN_BRIDGE_ADDRESS = getAddress(
+  CLUSTER === "mainnet"
+    ? "0x5848C791e09901b40A9Ef749f2a6735b418d7564"
+    : CLUSTER === "testnet"
+    ? "0x88d8004A9BdbfD9D28090A02010C19897a29605c"
+    : "0x0290FB167208Af455bB137780163b7B7a9a10C16"
+);
 export const SOL_BRIDGE_ADDRESS =
   CLUSTER === "mainnet"
     ? "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth"
@@ -399,6 +438,8 @@ export const getBridgeAddressForChain = (chainId: ChainId) =>
     ? ROPSTEN_ETH_BRIDGE_ADDRESS
     : chainId === CHAIN_ID_AVAX
     ? AVAX_BRIDGE_ADDRESS
+    : chainId === CHAIN_ID_OASIS
+    ? OASIS_BRIDGE_ADDRESS
     : "";
 export const getNFTBridgeAddressForChain = (chainId: ChainId) =>
   chainId === CHAIN_ID_SOLANA
@@ -413,6 +454,8 @@ export const getNFTBridgeAddressForChain = (chainId: ChainId) =>
     ? ROPSTEN_ETH_NFT_BRIDGE_ADDRESS
     : chainId === CHAIN_ID_AVAX
     ? AVAX_NFT_BRIDGE_ADDRESS
+    : chainId === CHAIN_ID_OASIS
+    ? OASIS_NFT_BRIDGE_ADDRESS
     : "";
 export const getTokenBridgeAddressForChain = (chainId: ChainId) =>
   chainId === CHAIN_ID_SOLANA
@@ -429,6 +472,8 @@ export const getTokenBridgeAddressForChain = (chainId: ChainId) =>
     ? ROPSTEN_ETH_TOKEN_BRIDGE_ADDRESS
     : chainId === CHAIN_ID_AVAX
     ? AVAX_TOKEN_BRIDGE_ADDRESS
+    : chainId === CHAIN_ID_OASIS
+    ? OASIS_TOKEN_BRIDGE_ADDRESS
     : "";
 
 export const COVALENT_API_KEY = process.env.REACT_APP_COVALENT_API_KEY
@@ -440,6 +485,7 @@ export const COVALENT_BSC = CLUSTER === "devnet" ? 56 : BSC_NETWORK_CHAIN_ID;
 export const COVALENT_POLYGON =
   CLUSTER === "devnet" ? 137 : POLYGON_NETWORK_CHAIN_ID;
 export const COVALENT_AVAX = CLUSTER === "devnet" ? 137 : AVAX_NETWORK_CHAIN_ID;
+export const COVALENT_OASIS = CLUSTER === "devnet" ? null : null;
 export const COVALENT_GET_TOKENS_URL = (
   chainId: ChainId,
   walletAddress: string,
@@ -455,6 +501,8 @@ export const COVALENT_GET_TOKENS_URL = (
       ? COVALENT_POLYGON
       : chainId === CHAIN_ID_AVAX
       ? COVALENT_AVAX
+      : chainId === CHAIN_ID_OASIS
+      ? COVALENT_OASIS
       : "";
   // 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}${
@@ -504,6 +552,14 @@ export const WAVAX_ADDRESS =
     : "0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E";
 export const WAVAX_DECIMALS = 18;
 
+export const WROSE_ADDRESS =
+  CLUSTER === "mainnet"
+    ? "0xE4F5F5910b347A5AEFd12745a98eEEA97F69180e"
+    : CLUSTER === "testnet"
+    ? "0x792296e2a15e6Ceb5f5039DecaE7A1f25b00B0B0"
+    : "0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E";
+export const WROSE_DECIMALS = 18;
+
 export const WORMHOLE_V1_ETH_ADDRESS =
   CLUSTER === "mainnet"
     ? "0xf92cD566Ea4864356C5491c177A430C222d7e678"