bridge_ui: landing page
fixes https://github.com/certusone/wormhole/issues/373 remove outdated TODOs Change-Id: I0b62bcb8bf6f9ab8a880c4a571df240c857f9bf1
This commit is contained in:
parent
496d2385f5
commit
bc34697ee4
|
@ -24,7 +24,9 @@
|
||||||
work correctly both with client-side routing and a non-root public URL.
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Sora:wght@300;400;500;700&display=swap" rel="stylesheet">
|
||||||
<title>Wormhole Token Bridge</title>
|
<title>Wormhole Token Bridge</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -9,8 +9,15 @@ import {
|
||||||
Typography,
|
Typography,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
import { GitHub, Publish, Send } from "@material-ui/icons";
|
import { GitHub, Publish, Send } from "@material-ui/icons";
|
||||||
import { NavLink, Redirect, Route, Switch } from "react-router-dom";
|
import {
|
||||||
|
Link as RouterLink,
|
||||||
|
NavLink,
|
||||||
|
Redirect,
|
||||||
|
Route,
|
||||||
|
Switch,
|
||||||
|
} from "react-router-dom";
|
||||||
import Attest from "./components/Attest";
|
import Attest from "./components/Attest";
|
||||||
|
import Home from "./components/Home";
|
||||||
import Transfer from "./components/Transfer";
|
import Transfer from "./components/Transfer";
|
||||||
import wormholeLogo from "./icons/wormhole.svg";
|
import wormholeLogo from "./icons/wormhole.svg";
|
||||||
|
|
||||||
|
@ -58,7 +65,13 @@ function App() {
|
||||||
<>
|
<>
|
||||||
<AppBar position="static" color="inherit" className={classes.appBar}>
|
<AppBar position="static" color="inherit" className={classes.appBar}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<img src={wormholeLogo} alt="Wormhole Logo" style={{ height: 52 }} />
|
<RouterLink to="/">
|
||||||
|
<img
|
||||||
|
src={wormholeLogo}
|
||||||
|
alt="Wormhole Logo"
|
||||||
|
style={{ height: 52 }}
|
||||||
|
/>
|
||||||
|
</RouterLink>
|
||||||
<div className={classes.spacer} />
|
<div className={classes.spacer} />
|
||||||
<Hidden implementation="css" xsDown>
|
<Hidden implementation="css" xsDown>
|
||||||
<div style={{ display: "flex", alignItems: "center" }}>
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
|
@ -132,8 +145,11 @@ function App() {
|
||||||
<Route exact path="/register">
|
<Route exact path="/register">
|
||||||
<Attest />
|
<Attest />
|
||||||
</Route>
|
</Route>
|
||||||
|
<Route exact path="/">
|
||||||
|
<Home />
|
||||||
|
</Route>
|
||||||
<Route>
|
<Route>
|
||||||
<Redirect to="/transfer" />
|
<Redirect to="/" />
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -46,7 +46,6 @@ function Target() {
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
{/* TODO: determine "to" token address */}
|
|
||||||
<KeyAndBalance chainId={targetChain} />
|
<KeyAndBalance chainId={targetChain} />
|
||||||
<ButtonWithLoader
|
<ButtonWithLoader
|
||||||
disabled={!isTargetComplete}
|
disabled={!isTargetComplete}
|
||||||
|
|
|
@ -18,8 +18,6 @@ import Source from "./Source";
|
||||||
import Target from "./Target";
|
import Target from "./Target";
|
||||||
import { Alert } from "@material-ui/lab";
|
import { Alert } from "@material-ui/lab";
|
||||||
|
|
||||||
// TODO: ensure that both wallets are connected to the same known network
|
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles(() => ({
|
||||||
rootContainer: {
|
rootContainer: {
|
||||||
backgroundColor: "rgba(0,0,0,0.2)",
|
backgroundColor: "rgba(0,0,0,0.2)",
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
Link,
|
||||||
|
makeStyles,
|
||||||
|
Typography,
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import { Link as RouterLink } from "react-router-dom";
|
||||||
|
import overview from "../../images/overview.svg";
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
rootContainer: {
|
||||||
|
backgroundColor: "rgba(0,0,0,0.2)",
|
||||||
|
margin: theme.spacing(4, 0),
|
||||||
|
padding: theme.spacing(4, 4),
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
marginBottom: theme.spacing(12),
|
||||||
|
[theme.breakpoints.down("sm")]: {
|
||||||
|
marginBottom: theme.spacing(6),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
fontWeight: 400,
|
||||||
|
marginBottom: theme.spacing(4),
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
marginBottom: theme.spacing(4),
|
||||||
|
},
|
||||||
|
overview: {
|
||||||
|
marginTop: theme.spacing(6),
|
||||||
|
[theme.breakpoints.down("sm")]: {
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
},
|
||||||
|
maxWidth: "100%",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
function Home() {
|
||||||
|
const classes = useStyles();
|
||||||
|
return (
|
||||||
|
<Container maxWidth="lg">
|
||||||
|
<div className={classes.rootContainer}>
|
||||||
|
<Typography variant="h3" className={classes.header}>
|
||||||
|
The portal is open.
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h6" className={classes.description}>
|
||||||
|
The Wormhole Token Bridge allows you to seamlessly transfer tokenized
|
||||||
|
assets across Solana and Ethereum.
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
component={RouterLink}
|
||||||
|
to="/transfer"
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
size="large"
|
||||||
|
className={classes.button}
|
||||||
|
>
|
||||||
|
Transfer Tokens
|
||||||
|
</Button>
|
||||||
|
<Typography variant="h6" className={classes.description}>
|
||||||
|
To learn more about the Wormhole Protocol that powers it, visit{" "}
|
||||||
|
<Link href="https://wormholenetwork.com/en/" color="secondary">
|
||||||
|
wormholenetwork.com
|
||||||
|
</Link>
|
||||||
|
</Typography>
|
||||||
|
<img src={overview} alt="overview" className={classes.overview} />
|
||||||
|
</div>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Home;
|
|
@ -31,7 +31,6 @@ export function useAssociatedAccountExistsState(
|
||||||
return;
|
return;
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
(async () => {
|
(async () => {
|
||||||
// TODO: share connection in context?
|
|
||||||
const connection = new Connection(SOLANA_HOST, "confirmed");
|
const connection = new Connection(SOLANA_HOST, "confirmed");
|
||||||
const mintPublicKey = new PublicKey(mintAddress);
|
const mintPublicKey = new PublicKey(mintAddress);
|
||||||
const payerPublicKey = new PublicKey(solPK); // currently assumes the wallet is the owner
|
const payerPublicKey = new PublicKey(solPK); // currently assumes the wallet is the owner
|
||||||
|
@ -86,7 +85,6 @@ export default function SolanaCreateAssociatedAddress({
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
(async () => {
|
(async () => {
|
||||||
// TODO: share connection in context?
|
|
||||||
const connection = new Connection(SOLANA_HOST, "confirmed");
|
const connection = new Connection(SOLANA_HOST, "confirmed");
|
||||||
const mintPublicKey = new PublicKey(mintAddress);
|
const mintPublicKey = new PublicKey(mintAddress);
|
||||||
const payerPublicKey = new PublicKey(solPK); // currently assumes the wallet is the owner
|
const payerPublicKey = new PublicKey(solPK); // currently assumes the wallet is the owner
|
||||||
|
|
|
@ -145,8 +145,8 @@ async function terra(tx: string) {
|
||||||
// TODO: move to wasm / sdk, share with solana
|
// TODO: move to wasm / sdk, share with solana
|
||||||
const parsePayload = (arr: Buffer) => ({
|
const parsePayload = (arr: Buffer) => ({
|
||||||
amount: BigNumber.from(arr.slice(1, 1 + 32)).toBigInt(),
|
amount: BigNumber.from(arr.slice(1, 1 + 32)).toBigInt(),
|
||||||
originAddress: arr.slice(33, 33 + 32).toString("hex"), // TODO: is this origin or source?
|
originAddress: arr.slice(33, 33 + 32).toString("hex"),
|
||||||
originChain: arr.readUInt16BE(65) as ChainId, // TODO: is this origin or source?
|
originChain: arr.readUInt16BE(65) as ChainId,
|
||||||
targetAddress: arr.slice(67, 67 + 32).toString("hex"),
|
targetAddress: arr.slice(67, 67 + 32).toString("hex"),
|
||||||
targetChain: arr.readUInt16BE(99) as ChainId,
|
targetChain: arr.readUInt16BE(99) as ChainId,
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,7 +17,7 @@ const useStyles = makeStyles((theme) => ({
|
||||||
export default function TargetPreview() {
|
export default function TargetPreview() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const targetChain = useSelector(selectTransferTargetChain);
|
const targetChain = useSelector(selectTransferTargetChain);
|
||||||
const targetAddress = useSelector(selectTransferTargetAddressHex); //TODO convert to readable
|
const targetAddress = useSelector(selectTransferTargetAddressHex);
|
||||||
const targetAddressNative = hexToNativeString(targetAddress, targetChain);
|
const targetAddressNative = hexToNativeString(targetAddress, targetChain);
|
||||||
|
|
||||||
const explainerString = targetAddressNative
|
const explainerString = targetAddressNative
|
||||||
|
|
|
@ -48,7 +48,6 @@ export default function TransferProgress() {
|
||||||
}
|
}
|
||||||
if (sourceChain === CHAIN_ID_SOLANA) {
|
if (sourceChain === CHAIN_ID_SOLANA) {
|
||||||
(async () => {
|
(async () => {
|
||||||
// TODO: share connection in context?
|
|
||||||
const connection = new Connection(SOLANA_HOST, "confirmed");
|
const connection = new Connection(SOLANA_HOST, "confirmed");
|
||||||
while (!cancelled) {
|
while (!cancelled) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 200));
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
||||||
|
|
|
@ -28,10 +28,6 @@ import Source from "./Source";
|
||||||
import SourcePreview from "./SourcePreview";
|
import SourcePreview from "./SourcePreview";
|
||||||
import Target from "./Target";
|
import Target from "./Target";
|
||||||
import TargetPreview from "./TargetPreview";
|
import TargetPreview from "./TargetPreview";
|
||||||
// TODO: ensure that both wallets are connected to the same known network
|
|
||||||
// TODO: loaders and such, navigation block?
|
|
||||||
// TODO: refresh displayed token amount after transfer somehow, could be resolved by having different components appear
|
|
||||||
// TODO: warn if amount exceeds balance
|
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles(() => ({
|
||||||
rootContainer: {
|
rootContainer: {
|
||||||
|
|
|
@ -86,7 +86,6 @@ async function solana(
|
||||||
) {
|
) {
|
||||||
dispatch(setIsSending(true));
|
dispatch(setIsSending(true));
|
||||||
try {
|
try {
|
||||||
// TODO: share connection in context?
|
|
||||||
const connection = new Connection(SOLANA_HOST, "confirmed");
|
const connection = new Connection(SOLANA_HOST, "confirmed");
|
||||||
const transaction = await attestFromSolana(
|
const transaction = await attestFromSolana(
|
||||||
connection,
|
connection,
|
||||||
|
|
|
@ -61,7 +61,6 @@ async function solana(
|
||||||
) {
|
) {
|
||||||
dispatch(setIsCreating(true));
|
dispatch(setIsCreating(true));
|
||||||
try {
|
try {
|
||||||
// TODO: share connection in context?
|
|
||||||
const connection = new Connection(SOLANA_HOST, "confirmed");
|
const connection = new Connection(SOLANA_HOST, "confirmed");
|
||||||
await postVaaSolana(
|
await postVaaSolana(
|
||||||
connection,
|
connection,
|
||||||
|
|
|
@ -67,7 +67,6 @@ async function solana(
|
||||||
) {
|
) {
|
||||||
dispatch(setIsRedeeming(true));
|
dispatch(setIsRedeeming(true));
|
||||||
try {
|
try {
|
||||||
// TODO: share connection in context?
|
|
||||||
const connection = new Connection(SOLANA_HOST, "confirmed");
|
const connection = new Connection(SOLANA_HOST, "confirmed");
|
||||||
await postVaaSolana(
|
await postVaaSolana(
|
||||||
connection,
|
connection,
|
||||||
|
|
|
@ -116,8 +116,6 @@ async function solana(
|
||||||
) {
|
) {
|
||||||
dispatch(setIsSending(true));
|
dispatch(setIsSending(true));
|
||||||
try {
|
try {
|
||||||
//TODO: check if token attestation exists on the target chain
|
|
||||||
// TODO: share connection in context?
|
|
||||||
const connection = new Connection(SOLANA_HOST, "confirmed");
|
const connection = new Connection(SOLANA_HOST, "confirmed");
|
||||||
const amountParsed = parseUnits(amount, decimals).toBigInt();
|
const amountParsed = parseUnits(amount, decimals).toBigInt();
|
||||||
const originAddress = originAddressStr
|
const originAddress = originAddressStr
|
||||||
|
@ -242,7 +240,6 @@ export function useHandleTransfer() {
|
||||||
const disabled = !isTargetComplete || isSending || isSendComplete;
|
const disabled = !isTargetComplete || isSending || isSendComplete;
|
||||||
const handleTransferClick = useCallback(() => {
|
const handleTransferClick = useCallback(() => {
|
||||||
// TODO: we should separate state for transaction vs fetching vaa
|
// TODO: we should separate state for transaction vs fetching vaa
|
||||||
// TODO: more generic way of calling these
|
|
||||||
if (
|
if (
|
||||||
sourceChain === CHAIN_ID_ETH &&
|
sourceChain === CHAIN_ID_ETH &&
|
||||||
!!signer &&
|
!!signer &&
|
||||||
|
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 53 KiB |
|
@ -9,6 +9,9 @@ export const theme = responsiveFontSizes(
|
||||||
paper: "#010114",
|
paper: "#010114",
|
||||||
},
|
},
|
||||||
divider: "#4e4e54",
|
divider: "#4e4e54",
|
||||||
|
text: {
|
||||||
|
primary: "rgba(255,255,255,0.98)",
|
||||||
|
},
|
||||||
primary: {
|
primary: {
|
||||||
main: "rgba(0, 116, 255, 0.8)", // #0074FF
|
main: "rgba(0, 116, 255, 0.8)", // #0074FF
|
||||||
},
|
},
|
||||||
|
@ -20,6 +23,9 @@ export const theme = responsiveFontSizes(
|
||||||
main: "#FD3503",
|
main: "#FD3503",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
typography: {
|
||||||
|
fontFamily: "'Sora', sans-serif",
|
||||||
|
},
|
||||||
overrides: {
|
overrides: {
|
||||||
MuiButton: {
|
MuiButton: {
|
||||||
root: {
|
root: {
|
||||||
|
|
|
@ -51,7 +51,6 @@ export async function getForeignAssetSol(
|
||||||
arrayify(originAsset, { hexPad: "left" }),
|
arrayify(originAsset, { hexPad: "left" }),
|
||||||
32
|
32
|
||||||
);
|
);
|
||||||
// TODO: share connection in context?
|
|
||||||
const connection = new Connection(SOLANA_HOST, "confirmed");
|
const connection = new Connection(SOLANA_HOST, "confirmed");
|
||||||
return await getForeignAssetSolanaTx(
|
return await getForeignAssetSolanaTx(
|
||||||
connection,
|
connection,
|
||||||
|
|
|
@ -45,7 +45,6 @@ export async function getOriginalAssetEth(
|
||||||
export async function getOriginalAssetSol(
|
export async function getOriginalAssetSol(
|
||||||
mintAddress: string
|
mintAddress: string
|
||||||
): Promise<StateSafeWormholeWrappedInfo> {
|
): Promise<StateSafeWormholeWrappedInfo> {
|
||||||
// TODO: share connection in context?
|
|
||||||
const connection = new Connection(SOLANA_HOST, "confirmed");
|
const connection = new Connection(SOLANA_HOST, "confirmed");
|
||||||
return makeStateSafe(
|
return makeStateSafe(
|
||||||
await getOriginalAssetSolTx(
|
await getOriginalAssetSolTx(
|
||||||
|
|
Loading…
Reference in New Issue