swap-ui/example/src/App.tsx

177 lines
4.8 KiB
TypeScript
Raw Normal View History

import "@fontsource/roboto";
2021-05-15 14:19:29 -07:00
import { useState, useEffect, useMemo } from "react";
2021-05-15 00:39:56 -07:00
import { SnackbarProvider, useSnackbar } from "notistack";
import { Button, Grid, makeStyles } from "@material-ui/core";
2021-05-12 13:10:52 -07:00
import { Provider } from "@project-serum/anchor";
2021-05-12 10:57:22 -07:00
// @ts-ignore
2021-05-12 13:10:52 -07:00
import Wallet from "@project-serum/sol-wallet-adapter";
2021-05-15 00:39:56 -07:00
import {
Signer,
2021-05-15 00:39:56 -07:00
ConfirmOptions,
Connection,
Transaction,
TransactionSignature,
} from "@solana/web3.js";
2021-05-15 14:19:29 -07:00
import {
TokenListContainer,
TokenListProvider,
} from "@solana/spl-token-registry";
import Swap from "@project-serum/swap-ui";
2021-05-12 13:10:52 -07:00
import "./App.css";
2021-05-12 10:57:22 -07:00
2021-05-15 00:39:56 -07:00
// App illustrating the use of the Swap component.
//
// One needs to just provide an Anchor `Provider` and a `TokenListContainer`
// to the `Swap` component, and then everything else is taken care of.
2021-05-12 10:57:22 -07:00
function App() {
2021-05-15 00:39:56 -07:00
return (
2021-05-15 16:16:28 -07:00
<SnackbarProvider maxSnack={5} autoHideDuration={8000}>
<AppInner />
</SnackbarProvider>
2021-05-15 00:39:56 -07:00
);
}
const useStyles = makeStyles((theme) => ({
root: {
minHeight: "100vh",
paddingLeft: theme.spacing(1),
paddingRight: theme.spacing(1),
},
}));
2021-05-15 00:39:56 -07:00
function AppInner() {
const styles = useStyles();
2021-05-15 00:39:56 -07:00
const { enqueueSnackbar } = useSnackbar();
2021-05-12 13:10:52 -07:00
const [isConnected, setIsConnected] = useState(false);
2021-05-15 14:19:29 -07:00
const [tokenList, setTokenList] = useState<TokenListContainer | null>(null);
2021-05-12 10:57:22 -07:00
2021-05-15 14:19:29 -07:00
const [provider, wallet] = useMemo(() => {
2021-05-12 13:10:52 -07:00
const opts: ConfirmOptions = {
preflightCommitment: "recent",
commitment: "recent",
};
2021-05-13 01:11:13 -07:00
const network = "https://solana-api.projectserum.com";
2021-05-12 13:10:52 -07:00
const wallet = new Wallet("https://www.sollet.io", network);
const connection = new Connection(network, opts.preflightCommitment);
2021-05-15 14:19:29 -07:00
const provider = new NotifyingProvider(
connection,
wallet,
opts,
(tx, err) => {
if (err) {
enqueueSnackbar(`Error: ${err.toString()}`, {
variant: "error",
});
} else {
enqueueSnackbar("Transaction sent", {
variant: "success",
action: (
<Button
color="inherit"
component="a"
target="_blank"
rel="noopener"
href={`https://explorer.solana.com/tx/${tx}`}
>
View on Solana Explorer
</Button>
),
});
}
}
);
return [provider, wallet];
}, [enqueueSnackbar]);
useEffect(() => {
new TokenListProvider().resolve().then(setTokenList);
}, [setTokenList]);
2021-05-12 10:57:22 -07:00
2021-05-12 13:10:52 -07:00
// Connect to the wallet.
useEffect(() => {
2021-05-15 14:19:29 -07:00
wallet.on("connect", () => {
enqueueSnackbar("Wallet connected", { variant: "success" });
setIsConnected(true);
});
wallet.on("disconnect", () => {
enqueueSnackbar("Wallet disconnected", { variant: "info" });
setIsConnected(false);
});
}, [wallet, enqueueSnackbar]);
2021-05-12 10:57:22 -07:00
2021-05-15 14:19:29 -07:00
return (
<Grid
container
justify="center"
alignItems="center"
className={styles.root}
2021-05-15 16:16:28 -07:00
>
2021-05-15 14:19:29 -07:00
<Button
variant="outlined"
onClick={() => (!isConnected ? wallet.connect() : wallet.disconnect())}
style={{ position: "fixed", right: 24, top: 24 }}
>
{!isConnected ? "Connect" : "Disconnect"}
</Button>
{tokenList && <Swap provider={provider} tokenList={tokenList} />}
</Grid>
2021-05-12 10:57:22 -07:00
);
}
2021-05-15 00:39:56 -07:00
// Custom provider to display notifications whenever a transaction is sent.
//
// Note that this is an Anchor wallet/network provider--not a React provider,
// so all transactions will be flowing through here, which allows us to
// hook in to display all transactions sent from the `Swap` component
// as notifications in the parent app.
class NotifyingProvider extends Provider {
// Function to call whenever the provider sends a transaction;
2021-05-15 14:19:29 -07:00
private onTransaction: (
tx: TransactionSignature | undefined,
err?: Error
) => void;
2021-05-15 00:39:56 -07:00
constructor(
connection: Connection,
wallet: Wallet,
opts: ConfirmOptions,
2021-05-15 14:19:29 -07:00
onTransaction: (tx: TransactionSignature | undefined, err?: Error) => void
2021-05-15 00:39:56 -07:00
) {
super(connection, wallet, opts);
this.onTransaction = onTransaction;
}
async send(
tx: Transaction,
signers?: Array<Signer | undefined>,
2021-05-15 00:39:56 -07:00
opts?: ConfirmOptions
): Promise<TransactionSignature> {
2021-05-15 14:19:29 -07:00
try {
const txSig = await super.send(tx, signers, opts);
this.onTransaction(txSig);
return txSig;
} catch (err) {
this.onTransaction(undefined, err);
2021-05-16 01:02:33 -07:00
return "";
2021-05-15 14:19:29 -07:00
}
2021-05-15 00:39:56 -07:00
}
async sendAll(
txs: Array<{ tx: Transaction; signers: Array<Signer | undefined> }>,
opts?: ConfirmOptions
): Promise<Array<TransactionSignature>> {
try {
const txSigs = await super.sendAll(txs, opts);
txSigs.forEach((sig) => {
this.onTransaction(sig);
});
return txSigs;
} catch (err) {
this.onTransaction(undefined, err);
return [];
}
}
2021-05-15 00:39:56 -07:00
}
2021-05-12 10:57:22 -07:00
export default App;