diff --git a/react/src/swapper/swapper.ts b/react/src/swapper/swapper.ts
index ae11198..394d17a 100644
--- a/react/src/swapper/swapper.ts
+++ b/react/src/swapper/swapper.ts
@@ -43,7 +43,7 @@ import {
swapExactOutFromVaaNativeV3,
swapExactOutFromVaaTokenV2,
swapExactOutFromVaaTokenV3,
-} from "util";
+} from "./util";
import { abi as SWAP_CONTRACT_V2_ABI } from "../abi/contracts/CrossChainSwapV2.json";
import { abi as SWAP_CONTRACT_V3_ABI } from "../abi/contracts/CrossChainSwapV3.json";
import { SWAP_CONTRACT_ADDRESS as CROSSCHAINSWAP_CONTRACT_ADDRESS_ETHEREUM } from "../addresses/goerli";
diff --git a/react/src/utils/consts.ts b/react/src/utils/consts.ts
index 07c46a6..d93824f 100644
--- a/react/src/utils/consts.ts
+++ b/react/src/utils/consts.ts
@@ -7,30 +7,51 @@ import ethIcon from "../icons/eth.svg";
import polygonIcon from "../icons/polygon.svg";
export interface TokenInfo {
- id: string;
name: string;
address: string;
chainId: ChainId;
logo: string;
+ isNative: boolean;
}
+export const MATIC_TOKEN_INFO: TokenInfo = {
+ name: "MATIC",
+ address: "0x9c3c9283d3e44854697cd22d3faa240cfb032889", // used to compute quote
+ chainId: CHAIN_ID_POLYGON,
+ logo: polygonIcon,
+ isNative: true,
+};
+
export const WMATIC_TOKEN_INFO: TokenInfo = {
- id: "WMATIC",
name: "WMATIC",
address: "0x9c3c9283d3e44854697cd22d3faa240cfb032889",
chainId: CHAIN_ID_POLYGON,
logo: polygonIcon,
+ isNative: false,
+};
+
+export const ETH_TOKEN_INFO: TokenInfo = {
+ name: "ETH",
+ address: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", // used to compute quote
+ chainId: CHAIN_ID_ETH,
+ logo: ethIcon,
+ isNative: true,
};
export const WETH_TOKEN_INFO: TokenInfo = {
- id: "WETH",
name: "WETH",
address: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6",
chainId: CHAIN_ID_ETH,
logo: ethIcon,
+ isNative: false,
};
-export const TOKEN_INFOS = [WMATIC_TOKEN_INFO, WETH_TOKEN_INFO];
+export const TOKEN_INFOS = [
+ MATIC_TOKEN_INFO,
+ WMATIC_TOKEN_INFO,
+ ETH_TOKEN_INFO,
+ WETH_TOKEN_INFO,
+];
export const ETH_NETWORK_CHAIN_ID = 5;
@@ -43,7 +64,7 @@ export const getEvmChainId = (chainId: ChainId) =>
? POLYGON_NETWORK_CHAIN_ID
: undefined;
-export const RELAYER_FEE_UST = "0.0001";
+export const RELAYER_FEE_UST = "0.25";
export const WORMHOLE_RPC_HOSTS = [
"https://wormhole-v2-testnet-api.certus.one",
diff --git a/react/src/utils/getIsTransferCompletedWithRetry.ts b/react/src/utils/getIsTransferCompletedWithRetry.ts
new file mode 100644
index 0000000..39463a8
--- /dev/null
+++ b/react/src/utils/getIsTransferCompletedWithRetry.ts
@@ -0,0 +1,31 @@
+import { getIsTransferCompletedEth } from "@certusone/wormhole-sdk";
+import { ethers } from "ethers";
+
+export default async function getIsTransferCompletedEvmWithRetry(
+ tokenBridgeAddress: string,
+ provider: ethers.providers.Provider,
+ signedVAA: Uint8Array,
+ retryTimeoutMs: number,
+ retryAttempts: number
+) {
+ let result = false;
+ let attempts = 0;
+ while (attempts < retryAttempts) {
+ try {
+ result = await getIsTransferCompletedEth(
+ tokenBridgeAddress,
+ provider,
+ signedVAA
+ );
+ console.log("getIsTransferCompletedEth", result);
+ } catch (e) {
+ console.error(e);
+ }
+ if (result) {
+ break;
+ }
+ await new Promise((resolve) => setTimeout(resolve, retryTimeoutMs));
+ attempts++;
+ }
+ return result;
+}
diff --git a/react/src/views/Home.tsx b/react/src/views/Home.tsx
index 532889c..3c76666 100644
--- a/react/src/views/Home.tsx
+++ b/react/src/views/Home.tsx
@@ -1,22 +1,26 @@
import {
Container,
+ Link,
makeStyles,
Paper,
TextField,
Typography,
} from "@material-ui/core";
-import { ChainId } from "@certusone/wormhole-sdk";
+import { ChainId, getSignedVAAWithRetry } from "@certusone/wormhole-sdk";
import { useCallback, useEffect, useState } from "react";
import ButtonWithLoader from "../components/ButtonWithLoader";
import EthereumSignerKey from "../components/EthereumSignerKey";
import TokenSelect from "../components/TokenSelect";
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
import {
+ ETH_TOKEN_INFO,
getEvmChainId,
+ MATIC_TOKEN_INFO,
RELAYER_FEE_UST,
TOKEN_INFOS,
WETH_TOKEN_INFO,
WMATIC_TOKEN_INFO,
+ WORMHOLE_RPC_HOSTS,
} from "../utils/consts";
import { COLORS } from "../muiTheme";
import Wormhole from "../icons/wormhole-network.svg";
@@ -28,6 +32,7 @@ import { useSnackbar } from "notistack";
import { Alert } from "@material-ui/lab";
import parseError from "../utils/parseError";
import Settings from "../components/Settings";
+import getIsTransferCompletedEvmWithRetry from "../utils/getIsTransferCompletedWithRetry";
const useStyles = makeStyles((theme) => ({
bg: {
@@ -160,7 +165,8 @@ export default function Home() {
const executor = new UniswapToUniswapExecutor();
await executor.initialize(
sourceTokenInfo.address,
- targetTokenInfo.address
+ targetTokenInfo.address,
+ sourceTokenInfo.isNative
);
await executor.computeAndVerifySrcPoolAddress().catch((e) => {
throw new Error("failed to verify source pool address");
@@ -225,12 +231,19 @@ export default function Home() {
}, []);
const handleSourceChange = useCallback((event) => {
+ // NOTE: only native-to-native or wrapped-to-wrapped swaps are currently supported
if (event.target.value === WMATIC_TOKEN_INFO.name) {
setSourceTokenInfo(WMATIC_TOKEN_INFO);
setTargetTokenInfo(WETH_TOKEN_INFO);
- } else {
+ } else if (event.target.value === WETH_TOKEN_INFO.name) {
setSourceTokenInfo(WETH_TOKEN_INFO);
setTargetTokenInfo(WMATIC_TOKEN_INFO);
+ } else if (event.target.value === ETH_TOKEN_INFO.name) {
+ setSourceTokenInfo(ETH_TOKEN_INFO);
+ setTargetTokenInfo(MATIC_TOKEN_INFO);
+ } else {
+ setSourceTokenInfo(MATIC_TOKEN_INFO);
+ setTargetTokenInfo(ETH_TOKEN_INFO);
}
setAmountIn("0.0");
setAmountOut("0.0");
@@ -242,13 +255,53 @@ export default function Home() {
setIsSwapping(true);
await switchProviderNetwork(provider, sourceTokenInfo.chainId);
const sourceReceipt = await executor.approveAndSwap(signer);
- console.info(`src transaction: ${sourceReceipt.transactionHash}`);
- await switchProviderNetwork(provider, targetTokenInfo.chainId);
- const targetReceipt = await executor.fetchVaaAndSwap(signer);
- console.info(`dst transaction: ${targetReceipt.transactionHash}`);
+ console.info(
+ "firstSwapTransactionHash:",
+ sourceReceipt.transactionHash
+ );
+
+ // Wait for the guardian network to reach consensus and emit the signedVAA
enqueueSnackbar(null, {
- content: