Skip to content

Commit

Permalink
bridge_ui: more safety checks and feedback messages
Browse files Browse the repository at this point in the history
fixes wormhole-foundation#372
fixes wormhole-foundation#366

Change-Id: Ieefdd2f04e353d4a68204864bfa91e8e8ebafc30
  • Loading branch information
evan-gray committed Sep 1, 2021
1 parent e11e590 commit b234c22
Show file tree
Hide file tree
Showing 17 changed files with 371 additions and 85 deletions.
55 changes: 55 additions & 0 deletions bridge_ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions bridge_ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
"@craco/craco": "^6.2.0",
"@truffle/hdwallet-provider": "^1.4.1",
"@types/node": "^16.6.1",
"@types/react-router-dom": "^5.1.8",
"prettier": "^2.3.2",
"truffle": "^5.4.1",
"wasm-loader": "^1.3.0"
Expand Down
89 changes: 60 additions & 29 deletions bridge_ui/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
Link,
makeStyles,
Toolbar,
Tooltip,
Typography,
} from "@material-ui/core";
import { GitHub, Publish, Send } from "@material-ui/icons";
import { NavLink, Redirect, Route, Switch } from "react-router-dom";
Expand All @@ -30,6 +32,9 @@ const useStyles = makeStyles((theme) => ({
...theme.typography.body1,
color: theme.palette.text.primary,
marginLeft: theme.spacing(6),
[theme.breakpoints.down("sm")]: {
marginLeft: theme.spacing(4),
},
[theme.breakpoints.down("xs")]: {
marginLeft: theme.spacing(2),
},
Expand Down Expand Up @@ -57,39 +62,65 @@ function App() {
<div className={classes.spacer} />
<Hidden implementation="css" xsDown>
<div style={{ display: "flex", alignItems: "center" }}>
<Link component={NavLink} to="/transfer" className={classes.link}>
Transfer
</Link>
<Link component={NavLink} to="/attest" className={classes.link}>
Attest
</Link>
<Tooltip title="Coming Soon">
<Typography
className={classes.link}
style={{ color: "#ffffff80", cursor: "default" }}
>
NFTs
</Typography>
</Tooltip>
<Tooltip title="Transfer tokens to another blockchain">
<Link
component={NavLink}
to="/transfer"
className={classes.link}
>
Transfer
</Link>
</Tooltip>
<Tooltip title="Register a new wrapped token">
<Link
component={NavLink}
to="/register"
className={classes.link}
>
Register
</Link>
</Tooltip>
<Tooltip title="View the source code">
<IconButton
href="https://github.com/certusone/wormhole"
target="_blank"
size="small"
className={classes.link}
>
<GitHub />
</IconButton>
</Tooltip>
</div>
</Hidden>
<Hidden implementation="css" smUp>
<Tooltip title="Transfer tokens to another blockchain">
<IconButton
href="https://github.com/certusone/wormhole"
target="_blank"
component={NavLink}
to="/transfer"
size="small"
className={classes.link}
>
<GitHub />
<Send />
</IconButton>
</div>
</Hidden>
<Hidden implementation="css" smUp>
<IconButton
component={NavLink}
to="/transfer"
size="small"
className={classes.link}
>
<Send />
</IconButton>
<IconButton
component={NavLink}
to="/attest"
size="small"
className={classes.link}
>
<Publish />
</IconButton>
</Tooltip>
<Tooltip title="Register a new wrapped token">
<IconButton
component={NavLink}
to="/register"
size="small"
className={classes.link}
>
<Publish />
</IconButton>
</Tooltip>
</Hidden>
</Toolbar>
</AppBar>
Expand All @@ -98,7 +129,7 @@ function App() {
<Route exact path="/transfer">
<Transfer />
</Route>
<Route exact path="/attest">
<Route exact path="/register">
<Attest />
</Route>
<Route>
Expand Down
29 changes: 29 additions & 0 deletions bridge_ui/src/ErrorBoundary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Typography } from "@material-ui/core";
import React from "react";

export default class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error) {
return { hasError: true };
}

componentDidCatch(error, errorInfo) {
console.error(error, errorInfo);
}

render() {
if (this.state.hasError) {
return (
<Typography variant="h5" style={{ textAlign: "center", marginTop: 24 }}>
An unexpected error has occurred. Please refresh the page.
</Typography>
);
}

return this.props.children;
}
}
7 changes: 6 additions & 1 deletion bridge_ui/src/components/Attest/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Create from "./Create";
import Send from "./Send";
import Source from "./Source";
import Target from "./Target";
import { Alert } from "@material-ui/lab";

// TODO: ensure that both wallets are connected to the same known network

Expand All @@ -24,6 +25,10 @@ function Attest() {
const signedVAAHex = useSelector(selectAttestSignedVAAHex);
return (
<Container maxWidth="md">
<Alert severity="info">
This form allows you to register a token on a new foreign chain. Tokens
must be registered before they can be transferred.
</Alert>
<Stepper activeStep={activeStep} orientation="vertical">
<Step>
<StepButton onClick={() => dispatch(setStep(0))}>
Expand Down Expand Up @@ -54,7 +59,7 @@ function Attest() {
onClick={() => dispatch(setStep(3))}
disabled={!signedVAAHex}
>
Create wrapper
Create wrapped token
</StepButton>
<StepContent>
<Create />
Expand Down
47 changes: 36 additions & 11 deletions bridge_ui/src/components/SolanaCreateAssociatedAddress.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
import { ChainId, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
import { Typography } from "@material-ui/core";
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
Token,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
import { Connection, PublicKey, Transaction } from "@solana/web3.js";
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
import { SOLANA_HOST } from "../utils/consts";
import { signSendAndConfirm } from "../utils/solana";
import ButtonWithLoader from "./ButtonWithLoader";

export default function SolanaCreateAssociatedAddress({
mintAddress,
readableTargetAddress,
}: {
mintAddress: string;
readableTargetAddress: string;
}) {
const [isCreating, setIsCreating] = useState(false);
export function useAssociatedAccountExistsState(
targetChain: ChainId,
mintAddress: string | null | undefined,
readableTargetAddress: string
) {
const [associatedAccountExists, setAssociatedAccountExists] = useState(true); // for now, assume it exists until we confirm it doesn't
const solanaWallet = useSolanaWallet();
const solPK = solanaWallet?.publicKey;
useEffect(() => {
setAssociatedAccountExists(true);
if (!mintAddress || !readableTargetAddress || !solPK) return;
if (
targetChain !== CHAIN_ID_SOLANA ||
!mintAddress ||
!readableTargetAddress ||
!solPK
)
return;
let cancelled = false;
(async () => {
// TODO: share connection in context?
Expand Down Expand Up @@ -52,7 +56,27 @@ export default function SolanaCreateAssociatedAddress({
return () => {
cancelled = true;
};
}, [mintAddress, readableTargetAddress, solPK]);
}, [targetChain, mintAddress, readableTargetAddress, solPK]);
return useMemo(
() => ({ associatedAccountExists, setAssociatedAccountExists }),
[associatedAccountExists]
);
}

export default function SolanaCreateAssociatedAddress({
mintAddress,
readableTargetAddress,
associatedAccountExists,
setAssociatedAccountExists,
}: {
mintAddress: string;
readableTargetAddress: string;
associatedAccountExists: boolean;
setAssociatedAccountExists: (associatedAccountExists: boolean) => void;
}) {
const [isCreating, setIsCreating] = useState(false);
const solanaWallet = useSolanaWallet();
const solPK = solanaWallet?.publicKey;
const handleClick = useCallback(() => {
if (
associatedAccountExists ||
Expand Down Expand Up @@ -100,6 +124,7 @@ export default function SolanaCreateAssociatedAddress({
})();
}, [
associatedAccountExists,
setAssociatedAccountExists,
mintAddress,
solPK,
readableTargetAddress,
Expand Down
21 changes: 21 additions & 0 deletions bridge_ui/src/components/StepDescription.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { makeStyles, Typography } from "@material-ui/core";
import { ReactChild } from "react";

const useStyles = makeStyles((theme) => ({
description: {
marginBottom: theme.spacing(4),
},
}));

export default function StepDescription({
children,
}: {
children: ReactChild;
}) {
const classes = useStyles();
return (
<Typography component="div" variant="body2" className={classes.description}>
{children}
</Typography>
);
}
Loading

0 comments on commit b234c22

Please sign in to comment.