UI - added bsc and avax support

This commit is contained in:
Kevin Peters 2022-01-31 18:36:15 +00:00
parent 8f363e8cc5
commit 0cf7d9e1c5
18 changed files with 189 additions and 236 deletions

View File

@ -1,2 +1,4 @@
REACT_APP_GOERLI_PROVIDER=https://goerli.infura.io/v3/YOUR-PROJECT-ID
REACT_APP_MUMBAI_PROVIDER=https://polygon-mumbai.infura.io/v3/YOUR-PROJECT-ID
REACT_APP_MUMBAI_PROVIDER=https://polygon-mumbai.infura.io/v3/YOUR-PROJECT-ID
REACT_APP_FUJI_PROVIDER=
REACT_APP_BSC_PROVIDER=

View File

@ -1,5 +1,2 @@
bsc.ts
fuji.ts
goerli.ts
mumbai.ts
*.ts
*.js

View File

@ -5,7 +5,7 @@ import Github from "../icons/Github.svg";
import Medium from "../icons/Medium.svg";
import Telegram from "../icons/Telegram.svg";
import Twitter from "../icons/Twitter.svg";
import Wormhole from "../icons/wormhole-network.svg";
import Wormhole from "../icons/wormhole_logo.svg";
const useStyles = makeStyles((theme) => ({
footer: {
@ -19,7 +19,6 @@ const useStyles = makeStyles((theme) => ({
},
},
builtWithContainer: {
display: "flex",
alignItems: "center",
justifyContent: "center",
opacity: 0.5,
@ -27,7 +26,7 @@ const useStyles = makeStyles((theme) => ({
},
wormholeIcon: {
height: 48,
width: 48,
width: 192,
filter: "contrast(0)",
transition: "filter 0.5s",
"&:hover": {
@ -92,24 +91,18 @@ export default function Footer() {
<img src={Twitter} alt="Twitter" />
</IconButton>
</div>
<div>
<a
href="https://wormholenetwork.com/"
target="_blank"
rel="noopener noreferrer"
>
<img src={Wormhole} alt="Wormhole" className={classes.wormholeIcon} />
</a>
</div>
<div className={classes.builtWithContainer}>
<div>
<a
href="https://wormholenetwork.com/"
target="_blank"
rel="noopener noreferrer"
>
<img
src={Wormhole}
alt="Wormhole"
className={classes.wormholeIcon}
/>
</a>
</div>
<div>
<Typography variant="body2">Open Source</Typography>
<Typography variant="body2">Built with &#10084;</Typography>
</div>
<Typography variant="body2">Open Source</Typography>
<Typography variant="body2">Built with &#10084;</Typography>
</div>
</footer>
);

View File

@ -1,7 +1,8 @@
import { ChainId, CHAIN_ID_POLYGON, isEVMChain } from "@certusone/wormhole-sdk";
import { ChainId, isEVMChain } from "@certusone/wormhole-sdk";
import { LinearProgress, makeStyles, Typography } from "@material-ui/core";
import { useEffect, useState } from "react";
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
import { getChainName } from "../utils/consts";
const useStyles = makeStyles((theme) => ({
root: {
@ -16,13 +17,11 @@ const useStyles = makeStyles((theme) => ({
export default function TransactionProgress({
chainId,
txBlockNumber,
isSourceSwapComplete,
hasSignedVAA,
isTargetSwapComplete,
}: {
chainId: ChainId;
txBlockNumber: number | undefined;
isSourceSwapComplete: boolean;
hasSignedVAA: boolean;
isTargetSwapComplete: boolean;
}) {
@ -51,20 +50,21 @@ export default function TransactionProgress({
};
}
}, [hasSignedVAA, chainId, provider, txBlockNumber]);
const blockDiff =
let blockDiff =
txBlockNumber !== undefined && txBlockNumber && currentBlock
? currentBlock - txBlockNumber
: 0;
const expectedBlocks = 15;
blockDiff = Math.min(Math.max(blockDiff, 0), expectedBlocks);
let value;
let valueBuffer;
let message;
if (!hasSignedVAA) {
value = (blockDiff / expectedBlocks) * 50;
valueBuffer = 50;
message = `Waiting for ${blockDiff} / ${expectedBlocks} confirmations on ${
chainId === CHAIN_ID_POLYGON ? "Polygon" : "Ethereum"
}...`;
message = `Waiting for ${blockDiff} / ${expectedBlocks} confirmations on ${getChainName(
chainId
)}...`;
} else if (!isTargetSwapComplete) {
value = 50;
valueBuffer = 100;

View File

@ -1,18 +1,10 @@
import {
ChainId,
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
isEVMChain,
} from "@certusone/wormhole-sdk";
import { ChainId, CHAIN_ID_TERRA, isEVMChain } from "@certusone/wormhole-sdk";
import { hexlify, hexStripZeros } from "@ethersproject/bytes";
import { useConnectedWallet } from "@terra-money/wallet-provider";
import { useCallback, useMemo } from "react";
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
// import { useSolanaWallet } from "../contexts/SolanaWalletContext";
import { getEvmChainId } from "../utils/consts";
const CLUSTER = "testnet"; // TODO: change this
const createWalletStatus = (
isReady: boolean,
statusMessage: string = "",
@ -35,8 +27,6 @@ function useIsWalletReady(
forceNetworkSwitch: () => void;
} {
const autoSwitch = enableNetworkAutoswitch;
// const solanaWallet = useSolanaWallet();
// const solPK = solanaWallet?.publicKey;
const terraWallet = useConnectedWallet();
const hasTerraWallet = !!terraWallet;
const {
@ -76,14 +66,6 @@ function useIsWalletReady(
);
}
if (isEVMChain(chainId) && hasEthInfo && signerAddress) {
//if (chainId === CHAIN_ID_SOLANA && solPK) {
// return createWalletStatus(
// true,
// undefined,
// forceNetworkSwitch,
// solPK.toString()
// );
//}
if (hasCorrectEvmNetwork) {
return createWalletStatus(
true,
@ -97,7 +79,7 @@ function useIsWalletReady(
}
return createWalletStatus(
false,
`Wallet is not connected to ${CLUSTER}. Expected Chain ID: ${correctEvmNetwork}`,
`Wallet is not connected to testnet. Expected Chain ID: ${correctEvmNetwork}`,
forceNetworkSwitch,
undefined
);
@ -115,7 +97,6 @@ function useIsWalletReady(
autoSwitch,
forceNetworkSwitch,
hasTerraWallet,
// solPK,
hasEthInfo,
correctEvmNetwork,
hasCorrectEvmNetwork,

15
react/src/icons/avax.svg Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 254 254" style="enable-background:new 0 0 254 254;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#E84142;}
.st1{fill:#FFFFFF;}
</style>
<g>
<circle class="st0" cx="127" cy="127" r="127"/>
<path class="st1" d="M171.8,130.3c4.4-7.6,11.5-7.6,15.9,0l27.4,48.1c4.4,7.6,0.8,13.8-8,13.8h-55.2c-8.7,0-12.3-6.2-8-13.8
L171.8,130.3z M118.8,37.7c4.4-7.6,11.4-7.6,15.8,0l6.1,11L155.1,74c3.5,7.2,3.5,15.7,0,22.9l-48.3,83.7
c-4.4,6.8-11.7,11.1-19.8,11.6H46.9c-8.8,0-12.4-6.1-8-13.8L118.8,37.7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 825 B

12
react/src/icons/bsc.svg Normal file
View File

@ -0,0 +1,12 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.3025 0L9.67897 6.12683L13.5847 8.39024L20.3025 4.52683L27.0204 8.39024L30.9261 6.12683L20.3025 0Z" fill="#F0B90B"/>
<path d="M27.0204 11.5902L30.9261 13.8537V18.3805L24.2083 22.2439V29.9707L20.3025 32.2341L16.3968 29.9707V22.2439L9.67897 18.3805V13.8537L13.5847 11.5902L20.3025 15.4537L27.0204 11.5902Z" fill="#F0B90B"/>
<path d="M30.9261 21.5805V26.1073L27.0204 28.3707V23.8439L30.9261 21.5805Z" fill="#F0B90B"/>
<path d="M26.9814 31.5707L33.6992 27.7073V19.9805L37.605 17.7171V29.9707L26.9814 36.0976V31.5707Z" fill="#F0B90B"/>
<path d="M33.6992 12.2537L29.7935 9.99025L33.6992 7.72683L37.605 9.99025V14.5171L33.6992 16.7805V12.2537Z" fill="#F0B90B"/>
<path d="M16.3968 37.7366V33.2098L20.3025 35.4732L24.2083 33.2098V37.7366L20.3025 40L16.3968 37.7366Z" fill="#F0B90B"/>
<path d="M13.5847 28.3707L9.67897 26.1073V21.5805L13.5847 23.8439V28.3707Z" fill="#F0B90B"/>
<path d="M20.3025 12.2537L16.3968 9.99025L20.3025 7.72683L24.2083 9.99025L20.3025 12.2537Z" fill="#F0B90B"/>
<path d="M10.8116 9.99025L6.90586 12.2537V16.7805L3.00012 14.5171V9.99025L6.90586 7.72683L10.8116 9.99025Z" fill="#F0B90B"/>
<path d="M3.00012 17.7171L6.90586 19.9805V27.7073L13.6237 31.5707V36.0976L3.00012 29.9707V17.7171Z" fill="#F0B90B"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,8 +0,0 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 73.18 86.09">
<defs>
<style>.cls-1{fill:red;}.cls-2{fill:#0073ff;}.cls-3{fill:#00f3d7;}</style>
</defs>
<path class="cls-1" d="M30.29,43.05A47.76,47.76,0,0,0,16.72,9.63a1.7,1.7,0,0,0-1.2-.5H4.34A1.67,1.67,0,0,0,2.67,10.8V22.29A1.69,1.69,0,0,0,4.24,24a19.15,19.15,0,0,1,0,38.18A1.68,1.68,0,0,0,2.67,63.8V75.29A1.68,1.68,0,0,0,4.34,77H15.52a1.66,1.66,0,0,0,1.2-.51A47.75,47.75,0,0,0,30.29,43.05Z"/>
<path class="cls-2" d="M70.51,63.8a1.68,1.68,0,0,0-1.57-1.66,19.15,19.15,0,0,1,0-38.18,1.69,1.69,0,0,0,1.57-1.67V10.8a1.67,1.67,0,0,0-1.67-1.67H57.66a1.7,1.7,0,0,0-1.2.5,47.93,47.93,0,0,0,0,66.83,1.66,1.66,0,0,0,1.2.51H68.84a1.68,1.68,0,0,0,1.67-1.68Z"/>
<path class="cls-3" d="M28.06,3.14a1.89,1.89,0,0,0-1.75,2.58,102.89,102.89,0,0,1,7.05,37.33,102.87,102.87,0,0,1-7,37.32A1.89,1.89,0,0,0,28.06,83h17a1.88,1.88,0,0,0,1.74-2.58,102.33,102.33,0,0,1,0-74.65,1.88,1.88,0,0,0-1.74-2.58Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 993 B

View File

@ -0,0 +1,23 @@
<svg id="Group_2616" data-name="Group 2616" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="176.577" height="30.781" viewBox="0 0 176.577 30.781">
<defs>
<clipPath id="clip-path">
<rect id="Rectangle_1331" data-name="Rectangle 1331" width="176.577" height="30.781" transform="translate(0 0)" fill="#fff"/>
</clipPath>
</defs>
<g id="Group_2614" data-name="Group 2614" transform="translate(0 0)" clip-path="url(#clip-path)">
<path id="Path_1571" data-name="Path 1571" d="M139.86,29.253l-4.039,11.421a.261.261,0,0,1-.268.177h-.306a.282.282,0,0,1-.273-.177l-3.028-8.01-3.023,8.01a.272.272,0,0,1-.268.177h-.311a.269.269,0,0,1-.268-.177l-4.039-11.417c-.062-.177.005-.287.177-.287h1.25a.26.26,0,0,1,.273.177l2.879,8.647,2.927-7.919a.277.277,0,0,1,.273-.177h.263a.271.271,0,0,1,.268.177l3.014,7.919,2.812-8.647a.26.26,0,0,1,.273-.177h1.231c.177,0,.244.11.182.283" transform="translate(-82.566 -19.288)" fill="#fff"/>
<path id="Path_1572" data-name="Path 1572" d="M200.285,34.471a5.96,5.96,0,1,1-5.96-6.017,5.879,5.879,0,0,1,5.96,6.017m-1.653,0c0-2.769-1.806-4.676-4.307-4.676s-4.307,1.907-4.307,4.676,1.806,4.676,4.307,4.676,4.307-1.907,4.307-4.676" transform="translate(-125.412 -18.944)" fill="#fff"/>
<path id="Path_1573" data-name="Path 1573" d="M253.32,40.186a.288.288,0,0,1-.254.474H251.94a.222.222,0,0,1-.182-.105l-2.826-4.264h-3.037v4.13a.243.243,0,0,1-.24.24h-1.1a.243.243,0,0,1-.239-.24V29.21a.244.244,0,0,1,.239-.24h4.326c3.028,0,4.523,1.591,4.523,3.66a3.445,3.445,0,0,1-2.841,3.469Zm-4.748-5.236c2.381,0,3.181-.987,3.181-2.319s-.8-2.319-3.181-2.319h-2.678v4.638Z" transform="translate(-162.664 -19.288)" fill="#fff"/>
<path id="Path_1574" data-name="Path 1574" d="M303.514,28.4h.359a.226.226,0,0,1,.24.24v11.4a.226.226,0,0,1-.24.24h-1.1a.226.226,0,0,1-.24-.24V31.947l-4.432,6.415a.182.182,0,0,1-.331,0l-4.431-6.415v8.092a.226.226,0,0,1-.24.24h-1.1a.226.226,0,0,1-.24-.24v-11.4a.226.226,0,0,1,.24-.24h.355a.36.36,0,0,1,.3.163l5.28,7.373,5.284-7.373a.346.346,0,0,1,.292-.163" transform="translate(-194.255 -18.906)" fill="#fff"/>
<path id="Path_1575" data-name="Path 1575" d="M361.126,29.21V40.42a.244.244,0,0,1-.24.24h-1.1a.244.244,0,0,1-.24-.24V35.313h-7.277V40.42a.244.244,0,0,1-.24.24h-1.1a.244.244,0,0,1-.24-.24V29.21a.244.244,0,0,1,.24-.24h1.1a.244.244,0,0,1,.24.24v4.762h7.277V29.21a.244.244,0,0,1,.24-.24h1.1a.244.244,0,0,1,.24.24" transform="translate(-233.489 -19.288)" fill="#fff"/>
<path id="Path_1576" data-name="Path 1576" d="M414.109,34.471a5.96,5.96,0,1,1-5.96-6.017,5.879,5.879,0,0,1,5.96,6.017m-1.653,0c0-2.769-1.806-4.676-4.307-4.676s-4.307,1.907-4.307,4.676,1.806,4.676,4.307,4.676,4.307-1.907,4.307-4.676" transform="translate(-267.773 -18.944)" fill="#fff"/>
<path id="Path_1577" data-name="Path 1577" d="M466.416,39.558v.862a.226.226,0,0,1-.24.24h-7.794a.244.244,0,0,1-.24-.24V29.21a.244.244,0,0,1,.24-.24h1.1a.244.244,0,0,1,.239.24V39.318h6.458a.226.226,0,0,1,.24.24" transform="translate(-305.025 -19.288)" fill="#fff"/>
<path id="Path_1578" data-name="Path 1578" d="M510.615,39.558v.862a.226.226,0,0,1-.24.24h-8.417a.244.244,0,0,1-.24-.24V29.21a.244.244,0,0,1,.24-.24h8.226a.226.226,0,0,1,.24.24v.862a.226.226,0,0,1-.24.24h-6.889v3.66h6.123a.225.225,0,0,1,.239.235v.867a.226.226,0,0,1-.239.239h-6.123v4.005h7.081a.226.226,0,0,1,.24.24" transform="translate(-334.038 -19.288)" fill="#fff"/>
<path id="Path_1579" data-name="Path 1579" d="M15.39,30.781a15.39,15.39,0,1,1,15.39-15.39,15.408,15.408,0,0,1-15.39,15.39m0-30.1A14.708,14.708,0,1,0,30.1,15.39,14.724,14.724,0,0,0,15.39.683" transform="translate(0 0)" fill="#fff"/>
<path id="Path_1580" data-name="Path 1580" d="M22.272,32.5A13.829,13.829,0,1,1,36.1,18.672,13.844,13.844,0,0,1,22.272,32.5m0-27.065A13.237,13.237,0,1,0,35.509,18.672,13.251,13.251,0,0,0,22.272,5.436" transform="translate(-5.622 -3.225)" fill="#fff"/>
<path id="Path_1581" data-name="Path 1581" d="M29.154,34.22A12.266,12.266,0,1,1,41.42,21.954,12.28,12.28,0,0,1,29.154,34.22m0-24.032A11.766,11.766,0,1,0,40.92,21.954,11.779,11.779,0,0,0,29.154,10.188" transform="translate(-11.244 -6.449)" fill="#fff"/>
<path id="Path_1582" data-name="Path 1582" d="M36.035,35.94a10.7,10.7,0,1,1,10.7-10.7,10.717,10.717,0,0,1-10.7,10.7m0-21A10.295,10.295,0,1,0,46.33,25.235,10.307,10.307,0,0,0,36.035,14.941" transform="translate(-16.865 -9.675)" fill="#fff"/>
<path id="Path_1583" data-name="Path 1583" d="M42.916,37.66a9.142,9.142,0,1,1,9.142-9.142,9.153,9.153,0,0,1-9.142,9.142m0-17.966a8.824,8.824,0,1,0,8.824,8.824,8.833,8.833,0,0,0-8.824-8.824" transform="translate(-22.486 -12.9)" fill="#fff"/>
<path id="Path_1584" data-name="Path 1584" d="M49.8,39.379a7.58,7.58,0,1,1,7.58-7.58,7.589,7.589,0,0,1-7.58,7.58m0-14.933A7.353,7.353,0,1,0,57.151,31.8,7.361,7.361,0,0,0,49.8,24.446" transform="translate(-28.108 -16.124)" fill="#fff"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -1,5 +1,3 @@
import { FixedNumber } from "ethers";
export enum UstLocation {
In = 1,
Out,

View File

@ -1,12 +1,12 @@
import { ethers } from "ethers";
import { WAVAX_TOKEN_INFO } from "../utils/consts";
import { AVAX_TOKEN_INFO } from "../utils/consts";
import { UstLocation } from "./generic";
import { UniswapV2Router } from "./uniswap-v2";
export { PROTOCOL } from "./uniswap-v2";
const HURRICANESWAP_FACTORY_ADDRESS = null;
const HURRICANESWAP_FACTORY_ADDRESS = "";
export class HurricaneswapRouter extends UniswapV2Router {
constructor(provider: ethers.providers.Provider) {
@ -15,7 +15,7 @@ export class HurricaneswapRouter extends UniswapV2Router {
}
async initialize(ustLocation: UstLocation): Promise<void> {
await super.initializeTokens(WAVAX_TOKEN_INFO, ustLocation);
await super.initializeTokens(AVAX_TOKEN_INFO, ustLocation);
return;
}

View File

@ -1,12 +1,12 @@
import { ethers } from "ethers";
import { WBNB_TOKEN_INFO } from "../utils/consts";
import { BNB_TOKEN_INFO } from "../utils/consts";
import { UstLocation } from "./generic";
import { UniswapV2Router } from "./uniswap-v2";
export { PROTOCOL } from "./uniswap-v2";
const PANCAKESWAP_FACTORY_ADDRESS = null;
const PANCAKESWAP_FACTORY_ADDRESS = "";
export class PancakeswapRouter extends UniswapV2Router {
constructor(provider: ethers.providers.Provider) {
@ -15,7 +15,7 @@ export class PancakeswapRouter extends UniswapV2Router {
}
async initialize(ustLocation: UstLocation): Promise<void> {
await super.initializeTokens(WBNB_TOKEN_INFO, ustLocation);
await super.initializeTokens(BNB_TOKEN_INFO, ustLocation);
return;
}

View File

@ -1,6 +1,6 @@
import { ethers } from "ethers";
import { WMATIC_TOKEN_INFO } from "../utils/consts";
import { MATIC_TOKEN_INFO } from "../utils/consts";
import { UstLocation } from "./generic";
import { UniswapV2Router } from "./uniswap-v2";
@ -15,7 +15,7 @@ export class QuickswapRouter extends UniswapV2Router {
}
async initialize(ustLocation: UstLocation): Promise<void> {
await super.initializeTokens(WMATIC_TOKEN_INFO, ustLocation);
await super.initializeTokens(MATIC_TOKEN_INFO, ustLocation);
return;
}
}

View File

@ -166,7 +166,7 @@ export abstract class UniswapRouterCore extends RouterCore {
const network = this.network;
if (ustLocation == UstLocation.Out) {
if (ustLocation === UstLocation.Out) {
[this.tokenIn, this.tokenOut] = await Promise.all([
makeUniEvmToken(this.provider, network.chainId, tokenInfo.address),
makeUniEvmToken(

View File

@ -14,7 +14,7 @@ import {
} from "@uniswap/v3-sdk";
import { UniswapRouterCore } from "./uniswap-core";
import { WETH_TOKEN_INFO } from "../utils/consts";
import { ETH_TOKEN_INFO } from "../utils/consts";
import { UstLocation } from "./generic";
export const PROTOCOL = "UniswapV3";
@ -34,7 +34,7 @@ export class UniswapV3Router extends UniswapRouterCore {
}
async initialize(ustLocation: UstLocation): Promise<void> {
await this.initializeTokens(WETH_TOKEN_INFO, ustLocation);
await this.initializeTokens(ETH_TOKEN_INFO, ustLocation);
return;
}

View File

@ -1,4 +1,4 @@
//@ts-nocheckk
//@ts-nocheck
import { ethers } from "ethers";
import { TransactionReceipt } from "@ethersproject/abstract-provider";
import {
@ -38,8 +38,6 @@ import {
//ETH_NETWORK_CHAIN_ID,
//POLYGON_NETWORK_CHAIN_ID,
//TERRA_NETWORK_CHAIN_ID,
WETH_TOKEN_INFO,
WMATIC_TOKEN_INFO,
UST_TOKEN_INFO,
} from "../utils/consts";
import {
@ -493,26 +491,28 @@ interface VaaSearchParams {
}
export function makeEvmProvider(tokenAddress: string) {
let url;
switch (tokenAddress) {
case WETH_TOKEN_INFO.address: {
const url = process.env.REACT_APP_GOERLI_PROVIDER;
if (!url) {
throw new Error("Could not find REACT_APP_GOERLI_PROVIDER");
}
return new ethers.providers.StaticJsonRpcProvider(url);
}
case WMATIC_TOKEN_INFO.address: {
const url = process.env.REACT_APP_MUMBAI_PROVIDER;
if (!url) {
throw new Error("Could not find REACT_APP_MUMBAI_PROVIDER");
}
return new ethers.providers.StaticJsonRpcProvider(url);
}
default: {
console.log("huh?", tokenAddress);
case ETH_TOKEN_INFO.address:
url = process.env.REACT_APP_GOERLI_PROVIDER;
if (!url) throw new Error("REACT_APP_GOERLI_PROVIDER not set");
break;
case MATIC_TOKEN_INFO.address:
url = process.env.REACT_APP_MUMBAI_PROVIDER;
if (!url) throw new Error("REACT_APP_MUMBAI_PROVIDER not set");
break;
case AVAX_TOKEN_INFO.address:
url = process.env.REACT_APP_FUJI_PROVIDER;
if (!url) throw new Error("REACT_APP_FUJI_PROVIDER not set");
break;
case BSC_TOKEN_INFO.address:
url = process.env.REACT_APP_BSC_PROVIDER;
if (!url) throw new Error("REACT_APP_BSC_PROVIDER not set");
break;
default:
throw Error("unrecognized token address");
}
}
return new ethers.providers.StaticJsonRpcProvider(url);
}
export class UniswapToUniswapExecutor {

View File

@ -7,169 +7,119 @@ import {
CHAIN_ID_BSC,
} from "@certusone/wormhole-sdk";
//import ethIcon from "../icons/eth.svg";
//import polygonIcon from "../icons/polygon.svg";
//import terraIcon from "../icons/terra.svg";
import ethIcon from "../icons/eth.svg";
import polygonIcon from "../icons/polygon.svg";
import terraIcon from "../icons/terra.svg";
import bscIcon from "../icons/bsc.svg";
import avaxIcon from "../icons/avax.svg";
const ethIcon = "";
const polygonIcon = "";
const bnbIcon = "";
const avaxIcon = "";
const terraIcon = "";
export const EVM_POLYGON_NETWORK_CHAIN_ID = 80001;
export const EVM_ETH_NETWORK_CHAIN_ID = 5;
export const EVM_AVAX_NETWORK_CHAIN_ID = 43113;
export const EVM_BSC_NETWORK_CHAIN_ID = 97;
export interface TokenInfo {
name: string;
address: string;
chainId: ChainId;
evmChainId: number | undefined;
logo: string;
isNative: boolean;
maxAmount: number;
ustPairedAddress: string | undefined;
}
// matic
export const MATIC_TOKEN_INFO: TokenInfo = {
name: "MATIC",
address: "0x9c3c9283d3e44854697cd22d3faa240cfb032889", // used to compute quote
chainId: CHAIN_ID_POLYGON,
logo: polygonIcon,
isNative: true,
maxAmount: 0.1,
ustPairedAddress: "0xe3a1c77e952b57b5883f6c906fc706fcc7d4392c",
};
export const WMATIC_TOKEN_INFO: TokenInfo = {
name: "WMATIC",
address: "0x9c3c9283d3e44854697cd22d3faa240cfb032889",
chainId: CHAIN_ID_POLYGON,
evmChainId: EVM_POLYGON_NETWORK_CHAIN_ID,
logo: polygonIcon,
isNative: false,
maxAmount: 0.1,
ustPairedAddress: "0xe3a1c77e952b57b5883f6c906fc706fcc7d4392c",
};
// eth
export const ETH_TOKEN_INFO: TokenInfo = {
name: "ETH",
address: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", // used to compute quote
chainId: CHAIN_ID_ETH,
logo: ethIcon,
isNative: true,
maxAmount: 0.01,
ustPairedAddress: "0x36Ed51Afc79619b299b238898E72ce482600568a",
};
export const WETH_TOKEN_INFO: TokenInfo = {
name: "WETH",
address: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
chainId: CHAIN_ID_ETH,
evmChainId: EVM_ETH_NETWORK_CHAIN_ID,
logo: ethIcon,
isNative: false,
maxAmount: 0.01,
ustPairedAddress: "0x36Ed51Afc79619b299b238898E72ce482600568a",
};
// avax
export const AVAX_TOKEN_INFO: TokenInfo = {
name: "AVAX",
address: "0x1d308089a2d1ced3f1ce36b1fcaf815b07217be3",
chainId: CHAIN_ID_AVAX,
evmChainId: EVM_AVAX_NETWORK_CHAIN_ID,
logo: avaxIcon,
isNative: true,
maxAmount: 0.01,
ustPairedAddress: "0xe09ed38e5cd1014444846f62376ac88c5232cde9",
};
export const WAVAX_TOKEN_INFO: TokenInfo = {
name: "WAVAX",
address: "0x1d308089a2d1ced3f1ce36b1fcaf815b07217be3",
chainId: CHAIN_ID_AVAX,
logo: avaxIcon,
isNative: false,
maxAmount: 0.01,
ustPairedAddress: "0xe09ed38e5cd1014444846f62376ac88c5232cde9",
};
// bnb
export const BNB_TOKEN_INFO: TokenInfo = {
name: "BNB",
address: "0xae13d989dac2f0debff460ac112a837c89baa7cd",
chainId: CHAIN_ID_BSC,
logo: bnbIcon,
isNative: true,
evmChainId: EVM_BSC_NETWORK_CHAIN_ID,
logo: bscIcon,
maxAmount: 0.01,
ustPairedAddress: "0x7b8eae1e85c8b189ee653d3f78733f4f788bb2c1",
};
export const WBNB_TOKEN_INFO: TokenInfo = {
name: "WBNB",
address: "0xae13d989dac2f0debff460ac112a837c89baa7cd",
chainId: CHAIN_ID_BSC,
logo: bnbIcon,
isNative: false,
maxAmount: 0.01,
ustPairedAddress: "0x7b8eae1e85c8b189ee653d3f78733f4f788bb2c1",
};
// ust
export const UST_TOKEN_INFO: TokenInfo = {
name: "UST",
address: "uusd",
chainId: CHAIN_ID_TERRA,
evmChainId: undefined,
logo: terraIcon,
isNative: true, // TODO: change?
maxAmount: 10.0,
ustPairedAddress: undefined,
};
export const TOKEN_INFOS = [
MATIC_TOKEN_INFO,
WMATIC_TOKEN_INFO,
ETH_TOKEN_INFO,
WETH_TOKEN_INFO,
UST_TOKEN_INFO,
AVAX_TOKEN_INFO,
BNB_TOKEN_INFO,
// TODO: support swaps from/to terra
// UST_TOKEN_INFO,
];
export const getSupportedSwaps = (tokenInfo: TokenInfo) => {
switch (tokenInfo) {
case MATIC_TOKEN_INFO:
return [ETH_TOKEN_INFO, UST_TOKEN_INFO];
case WMATIC_TOKEN_INFO:
return [WETH_TOKEN_INFO];
case ETH_TOKEN_INFO:
return [MATIC_TOKEN_INFO, UST_TOKEN_INFO];
case WETH_TOKEN_INFO:
return [WMATIC_TOKEN_INFO];
case UST_TOKEN_INFO:
return [ETH_TOKEN_INFO, MATIC_TOKEN_INFO];
}
return [];
return TOKEN_INFOS.filter((x) => x !== tokenInfo);
};
export const EVM_ETH_NETWORK_CHAIN_ID = 5;
export const EVM_POLYGON_NETWORK_CHAIN_ID = 80001;
export const EVM_AVAX_NETWORK_CHAIN_ID = 43113;
export const EVM_BSC_NETWORK_CHAIN_ID = 97;
export function getEvmChainId(chainId: ChainId): number {
export const getEvmChainId = (chainId: ChainId): number | undefined => {
switch (chainId) {
case CHAIN_ID_ETH: {
case CHAIN_ID_ETH:
return EVM_ETH_NETWORK_CHAIN_ID;
}
case CHAIN_ID_POLYGON: {
case CHAIN_ID_POLYGON:
return EVM_POLYGON_NETWORK_CHAIN_ID;
}
case CHAIN_ID_AVAX: {
case CHAIN_ID_AVAX:
return EVM_AVAX_NETWORK_CHAIN_ID;
}
case CHAIN_ID_BSC: {
case CHAIN_ID_BSC:
return EVM_BSC_NETWORK_CHAIN_ID;
}
default: {
default:
return undefined;
}
}
}
};
export const getChainName = (chainId: ChainId) => {
switch (chainId) {
case CHAIN_ID_ETH:
return "Ethereum";
case CHAIN_ID_POLYGON:
return "Polygon";
case CHAIN_ID_AVAX:
return "Avalanche";
case CHAIN_ID_BSC:
return "BSC";
default:
return "";
}
};
export const RELAYER_FEE_UST = "0.25";

View File

@ -39,11 +39,7 @@ import parseError from "../utils/parseError";
import Settings from "../components/Settings";
import getIsTransferCompletedEvmWithRetry from "../utils/getIsTransferCompletedWithRetry";
import CircleLoader from "../components/CircleLoader";
import {
ArrowForward,
CheckCircleOutlineRounded,
QueueTwoTone,
} from "@material-ui/icons";
import { ArrowForward, CheckCircleOutlineRounded } from "@material-ui/icons";
import SwapProgress from "../components/SwapProgress";
import Footer from "../components/Footer";
import TerraWalletKey from "../components/TerraWalletKey";
@ -163,13 +159,19 @@ const switchEvmProviderNetwork = async (
}
};
const ConnectedWalletAddress = ({ chainId }: { chainId: ChainId }) => {
const ConnectedWalletAddress = ({
chainId,
prefix,
}: {
chainId: ChainId;
prefix: string;
}) => {
const { walletAddress } = useIsWalletReady(chainId, false);
if (walletAddress) {
const is0x = walletAddress.startsWith("0x");
return (
<Typography variant="subtitle2">
{walletAddress?.substring(0, is0x ? 6 : 3)}...
{prefix} {walletAddress?.substring(0, is0x ? 6 : 3)}...
{walletAddress?.substring(walletAddress.length - (is0x ? 4 : 3))}
</Typography>
);
@ -190,16 +192,13 @@ const SwapButton = ({
showLoader: boolean;
onClick: () => void;
}) => {
const { isReady: isSourceWalletReady, walletAddress: sourceWalletAddress } =
useIsWalletReady(source.chainId, false);
const { isReady: isTargetWalletReady, walletAddress: targetWalletAddress } =
useIsWalletReady(target.chainId, false);
console.log(
"sourceWalletAddress",
sourceWalletAddress,
"targetWalletAddress",
targetWalletAddress
const { isReady: isSourceWalletReady } = useIsWalletReady(
source.chainId,
!disabled
);
const { isReady: isTargetWalletReady } = useIsWalletReady(
target.chainId,
!isEVMChain(source.chainId)
);
if (!isSourceWalletReady) {
@ -220,6 +219,7 @@ const SwapButton = ({
<TerraWalletKey />
) : null;
}
return (
<ButtonWithLoader
disabled={disabled}
@ -246,7 +246,7 @@ export default function Home() {
const [isSwapping, setIsSwapping] = useState(false);
const [isComputingQuote, setIsComputingQuote] = useState(false);
const [hasQuote, setHasQuote] = useState(false);
const { provider, signer } = useEthereumProvider();
const { provider, signer, signerAddress, disconnect } = useEthereumProvider();
const { enqueueSnackbar } = useSnackbar();
const [isSourceSwapComplete, setIsSourceSwapComplete] = useState(false);
const [isTargetSwapComplete, setIsTargetSwapComplete] = useState(false);
@ -256,8 +256,6 @@ export default function Home() {
const [hasSignedVAA, setHasSignedVAA] = useState(false);
const [relayerTimeoutString, setRelayerTimeoutString] = useState("");
const foo = useIsWalletReady(sourceTokenInfo.chainId);
const computeQuote = useCallback(() => {
(async () => {
setHasQuote(false);
@ -274,7 +272,7 @@ export default function Home() {
await executor.initialize(
sourceTokenInfo.address,
targetTokenInfo.address,
sourceTokenInfo.isNative
true
);
await executor.computeAndVerifySrcPoolAddress().catch((e) => {
throw new Error("failed to verify source pool address");
@ -286,23 +284,9 @@ export default function Home() {
executor.setSlippage((parseFloat(slippage) / 100).toString());
executor.setRelayerFee(RELAYER_FEE_UST);
const quote = await executor.computeQuoteExactIn(amountIn);
// TODO: FIX
if (!quote || !quote.dst) {
throw new Error("failed to compute quote");
}
setExecutor(executor);
setAmountOut(
parseFloat(
// executor.tokens.dstOut.formatAmount(quote.dst.minAmountOut)
quote.minAmountOut
).toFixed(8)
);
setAmountInUST(
parseFloat(
//executor.tokens.dstIn.formatAmount(quote.dst.amountIn)
quote.ustAmountIn
).toFixed(2)
);
setAmountOut(parseFloat(quote.minAmountOut).toFixed(8));
setAmountInUST(parseFloat(quote.ustAmountIn).toFixed(2));
setHasQuote(true);
}
} catch (e) {
@ -352,7 +336,6 @@ export default function Home() {
const tokenInfo = TOKEN_INFOS.find((x) => x.name === event.target.value);
if (tokenInfo) {
const supportedSwaps = getSupportedSwaps(tokenInfo);
console.log(supportedSwaps);
if (supportedSwaps) {
setSourceTokenInfo(tokenInfo);
if (!supportedSwaps.find((x) => x.name === targetTokenInfo.name)) {
@ -378,15 +361,17 @@ export default function Home() {
setIsSwapping(false);
setHasQuote(false);
setIsSourceSwapComplete(false);
setHasSignedVAA(false);
setIsTargetSwapComplete(false);
setAmountIn("");
setAmountOut("");
setSourceTxBlockNumber(undefined);
setRelayerTimeoutString("");
}, []);
disconnect();
}, [disconnect]);
const handleSwapClick = useCallback(async () => {
if (provider && signer && executor) {
if (provider && signer && signerAddress && executor) {
try {
setIsSwapping(true);
setIsSourceSwapComplete(false);
@ -394,9 +379,12 @@ export default function Home() {
setIsTargetSwapComplete(false);
setRelayerTimeoutString("");
await switchEvmProviderNetwork(provider, sourceTokenInfo.chainId);
console.log(signerAddress);
// TODO: fix
const sourceReceipt = await executor.evmApproveAndSwap(signer);
const sourceReceipt = await executor.evmApproveAndSwap(
signer,
signerAddress
);
console.info(
"firstSwapTransactionHash:",
sourceReceipt.transactionHash
@ -415,8 +403,8 @@ export default function Home() {
// Check if the signedVAA has redeemed by the relayer
const isCompleted = await getIsTransferCompletedEvmWithRetry(
executor.dstExecutionParams.wormhole.tokenBridgeAddress,
// TODO: fix
//@ts-ignore
// TODO: fix typescript error
// @ts-ignore
executor.quoter.getDstEvmProvider(),
vaaBytes,
// retry for two minutes
@ -447,6 +435,7 @@ export default function Home() {
}, [
provider,
signer,
signerAddress,
executor,
enqueueSnackbar,
sourceTokenInfo,
@ -461,9 +450,7 @@ export default function Home() {
<div className={classes.bg}>
<Container className={classes.centeredContainer} maxWidth="sm">
<div className={classes.titleBar}></div>
<Typography variant="h4" color="textSecondary">
Wormhole NativeSwap Demo
</Typography>
<Typography variant="h4">Wormhole NativeSwap Demo</Typography>
<div className={classes.spacer} />
<Paper className={classes.mainPaper}>
<Collapse in={!isSourceSwapComplete}>
@ -496,7 +483,10 @@ export default function Home() {
color="error"
>{`The max input amount is ${sourceTokenInfo.maxAmount} ${sourceTokenInfo.name}`}</Typography>
) : null}
<ConnectedWalletAddress chainId={sourceTokenInfo.chainId} />
<ConnectedWalletAddress
chainId={sourceTokenInfo.chainId}
prefix="From:"
/>
<div className={classes.spacer} />
<TokenSelect
tokens={getSupportedSwaps(sourceTokenInfo)}
@ -521,6 +511,7 @@ export default function Home() {
? sourceTokenInfo.chainId
: targetTokenInfo.chainId
}
prefix="To:"
/>
<div className={classes.spacer} />
<Typography variant="subtitle2">{`Slippage tolerance: ${slippage}%`}</Typography>
@ -575,7 +566,6 @@ export default function Home() {
<SwapProgress
chainId={sourceTokenInfo.chainId}
txBlockNumber={sourceTxBlockNumber}
isSourceSwapComplete={isSourceSwapComplete}
hasSignedVAA={hasSignedVAA}
isTargetSwapComplete={isTargetSwapComplete}
/>