UI - native swap and relayer support
This commit is contained in:
parent
237d06b558
commit
c1ae41d6d8
|
@ -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";
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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}`);
|
||||
console.info(
|
||||
"firstSwapTransactionHash:",
|
||||
sourceReceipt.transactionHash
|
||||
);
|
||||
|
||||
// Wait for the guardian network to reach consensus and emit the signedVAA
|
||||
enqueueSnackbar(null, {
|
||||
content: <Alert severity="info">Fetching VAA</Alert>,
|
||||
});
|
||||
const { vaaBytes } = await getSignedVAAWithRetry(
|
||||
WORMHOLE_RPC_HOSTS,
|
||||
executor.srcExecutionParams.wormhole.chainId,
|
||||
executor.vaaSearchParams.emitterAddress,
|
||||
executor.vaaSearchParams.sequence
|
||||
);
|
||||
// Check if the signedVAA has redeemed by the relayer
|
||||
enqueueSnackbar(null, {
|
||||
content: (
|
||||
<Alert severity="info">
|
||||
Fetched the Signed VAA, waiting for relayer to redeem it
|
||||
</Alert>
|
||||
),
|
||||
});
|
||||
const isCompleted = await getIsTransferCompletedEvmWithRetry(
|
||||
executor.dstExecutionParams.wormhole.tokenBridgeAddress,
|
||||
executor.quoter.dstProvider, //provider,
|
||||
vaaBytes,
|
||||
// retry for two minutes
|
||||
3000,
|
||||
40
|
||||
);
|
||||
if (isCompleted) {
|
||||
enqueueSnackbar(null, {
|
||||
content: <Alert severity="success">Swap completed</Alert>,
|
||||
});
|
||||
} else {
|
||||
// If the relayer hasn't redeemed the signedVAA, then manually redeem it ourselves
|
||||
await switchProviderNetwork(provider, targetTokenInfo.chainId);
|
||||
const targetReceipt = await executor.fetchVaaAndSwap(signer);
|
||||
console.info(`dst transaction: ${targetReceipt.transactionHash}`);
|
||||
enqueueSnackbar(null, {
|
||||
content: <Alert severity="success">Success!</Alert>,
|
||||
content: <Alert severity="success">Swap completed</Alert>,
|
||||
});
|
||||
console.info(
|
||||
"secondSwapTransactionHash:",
|
||||
targetReceipt.transactionHash
|
||||
);
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
enqueueSnackbar(null, {
|
||||
|
@ -329,6 +382,12 @@ export default function Home() {
|
|||
{"powered by wormhole"}
|
||||
</Typography>
|
||||
<img src={Wormhole} alt="Wormhole" className={classes.wormholeIcon} />
|
||||
<div className={classes.spacer} />
|
||||
<Link variant="subtitle2" href="https://goerli-faucet.slock.it/">
|
||||
Goerli faucet
|
||||
</Link>
|
||||
<div />
|
||||
<Link href="https://faucet.polygon.technology/">Mumbai faucet</Link>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue