all the ui components for lp_ui
Change-Id: I60b6f95f480c28f245e87f35fd7ae4ebdced535d
This commit is contained in:
parent
8a90b50aeb
commit
1230ea6fa3
|
@ -0,0 +1,72 @@
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
CircularProgress,
|
||||||
|
makeStyles,
|
||||||
|
Typography,
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import { ReactChild } from "react";
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
root: {
|
||||||
|
position: "relative",
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
textTransform: "none",
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
loader: {
|
||||||
|
position: "absolute",
|
||||||
|
bottom: 0,
|
||||||
|
left: "50%",
|
||||||
|
marginLeft: -12,
|
||||||
|
marginBottom: 6,
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
marginTop: theme.spacing(1),
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function ButtonWithLoader({
|
||||||
|
disabled,
|
||||||
|
onClick,
|
||||||
|
showLoader,
|
||||||
|
error,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
disabled?: boolean;
|
||||||
|
onClick: () => void;
|
||||||
|
showLoader?: boolean;
|
||||||
|
error?: string;
|
||||||
|
children: ReactChild;
|
||||||
|
}) {
|
||||||
|
const classes = useStyles();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={classes.root}>
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
variant="contained"
|
||||||
|
className={classes.button}
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Button>
|
||||||
|
{showLoader ? (
|
||||||
|
<CircularProgress
|
||||||
|
size={24}
|
||||||
|
color="inherit"
|
||||||
|
className={classes.loader}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
{error ? (
|
||||||
|
<Typography color="error" className={classes.error}>
|
||||||
|
{error}
|
||||||
|
</Typography>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
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, useMemo, useState } from "react";
|
||||||
|
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
||||||
|
import { SOLANA_URL } from "../utils/consts";
|
||||||
|
import { signSendAndConfirm } from "../utils/solana";
|
||||||
|
import ButtonWithLoader from "./ButtonWithLoader";
|
||||||
|
|
||||||
|
export function useAssociatedAccountExistsState(
|
||||||
|
mintAddress: string | null | undefined,
|
||||||
|
readableTargetAddress: string | undefined
|
||||||
|
) {
|
||||||
|
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;
|
||||||
|
let cancelled = false;
|
||||||
|
(async () => {
|
||||||
|
const connection = new Connection(SOLANA_URL, "confirmed");
|
||||||
|
const mintPublicKey = new PublicKey(mintAddress);
|
||||||
|
const payerPublicKey = new PublicKey(solPK); // currently assumes the wallet is the owner
|
||||||
|
const associatedAddress = await Token.getAssociatedTokenAddress(
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
mintPublicKey,
|
||||||
|
payerPublicKey
|
||||||
|
);
|
||||||
|
const match = associatedAddress.toString() === readableTargetAddress;
|
||||||
|
if (match) {
|
||||||
|
const associatedAddressInfo = await connection.getAccountInfo(
|
||||||
|
associatedAddress
|
||||||
|
);
|
||||||
|
if (!associatedAddressInfo) {
|
||||||
|
if (!cancelled) {
|
||||||
|
setAssociatedAccountExists(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, [mintAddress, readableTargetAddress, solPK]);
|
||||||
|
return useMemo(
|
||||||
|
() => ({ associatedAccountExists, setAssociatedAccountExists }),
|
||||||
|
[associatedAccountExists]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SolanaCreateAssociatedAddress({
|
||||||
|
mintAddress,
|
||||||
|
readableTargetAddress,
|
||||||
|
associatedAccountExists,
|
||||||
|
setAssociatedAccountExists,
|
||||||
|
}: {
|
||||||
|
mintAddress: string | undefined;
|
||||||
|
readableTargetAddress: string | undefined;
|
||||||
|
associatedAccountExists: boolean;
|
||||||
|
setAssociatedAccountExists: (associatedAccountExists: boolean) => void;
|
||||||
|
}) {
|
||||||
|
const [isCreating, setIsCreating] = useState(false);
|
||||||
|
const solanaWallet = useSolanaWallet();
|
||||||
|
const solPK = solanaWallet?.publicKey;
|
||||||
|
const handleClick = useCallback(() => {
|
||||||
|
if (
|
||||||
|
associatedAccountExists ||
|
||||||
|
!mintAddress ||
|
||||||
|
!readableTargetAddress ||
|
||||||
|
!solPK
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const connection = new Connection(SOLANA_URL, "confirmed");
|
||||||
|
const mintPublicKey = new PublicKey(mintAddress);
|
||||||
|
const payerPublicKey = new PublicKey(solPK); // currently assumes the wallet is the owner
|
||||||
|
const associatedAddress = await Token.getAssociatedTokenAddress(
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
mintPublicKey,
|
||||||
|
payerPublicKey
|
||||||
|
);
|
||||||
|
const match = associatedAddress.toString() === readableTargetAddress;
|
||||||
|
if (match) {
|
||||||
|
const associatedAddressInfo = await connection.getAccountInfo(
|
||||||
|
associatedAddress
|
||||||
|
);
|
||||||
|
if (!associatedAddressInfo) {
|
||||||
|
setIsCreating(true);
|
||||||
|
const transaction = new Transaction().add(
|
||||||
|
await Token.createAssociatedTokenAccountInstruction(
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
mintPublicKey,
|
||||||
|
associatedAddress,
|
||||||
|
payerPublicKey, // owner
|
||||||
|
payerPublicKey // payer
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const { blockhash } = await connection.getRecentBlockhash();
|
||||||
|
transaction.recentBlockhash = blockhash;
|
||||||
|
transaction.feePayer = new PublicKey(payerPublicKey);
|
||||||
|
await signSendAndConfirm(solanaWallet, connection, transaction);
|
||||||
|
setIsCreating(false);
|
||||||
|
setAssociatedAccountExists(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("cannot create specified spl token account");
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, [
|
||||||
|
associatedAccountExists,
|
||||||
|
setAssociatedAccountExists,
|
||||||
|
mintAddress,
|
||||||
|
solPK,
|
||||||
|
readableTargetAddress,
|
||||||
|
solanaWallet,
|
||||||
|
]);
|
||||||
|
if (associatedAccountExists) return null;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Typography color="error" variant="body2">
|
||||||
|
This associated token account doesn't exist.
|
||||||
|
</Typography>
|
||||||
|
<ButtonWithLoader
|
||||||
|
disabled={
|
||||||
|
!mintAddress || !readableTargetAddress || !solPK || isCreating
|
||||||
|
}
|
||||||
|
onClick={handleClick}
|
||||||
|
showLoader={isCreating}
|
||||||
|
>
|
||||||
|
Create Associated Token Account
|
||||||
|
</ButtonWithLoader>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -2,17 +2,20 @@ import { CssBaseline } from "@material-ui/core";
|
||||||
import { ThemeProvider } from "@material-ui/core/styles";
|
import { ThemeProvider } from "@material-ui/core/styles";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
|
import ErrorBoundary from "./components/ErrorBoundary";
|
||||||
import { LoggerProvider } from "./contexts/Logger";
|
import { LoggerProvider } from "./contexts/Logger";
|
||||||
import { SolanaWalletProvider } from "./contexts/SolanaWalletContext";
|
import { SolanaWalletProvider } from "./contexts/SolanaWalletContext";
|
||||||
import { theme } from "./muiTheme";
|
import { theme } from "./muiTheme";
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<ThemeProvider theme={theme}>
|
<ErrorBoundary>
|
||||||
<CssBaseline />
|
<ThemeProvider theme={theme}>
|
||||||
<SolanaWalletProvider>
|
<CssBaseline />
|
||||||
<LoggerProvider>
|
<SolanaWalletProvider>
|
||||||
<App />
|
<LoggerProvider>
|
||||||
</LoggerProvider>
|
<App />
|
||||||
</SolanaWalletProvider>
|
</LoggerProvider>
|
||||||
</ThemeProvider>,
|
</SolanaWalletProvider>
|
||||||
|
</ThemeProvider>
|
||||||
|
</ErrorBoundary>,
|
||||||
document.getElementById("root")
|
document.getElementById("root")
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
Paper,
|
Paper,
|
||||||
TextField,
|
TextField,
|
||||||
Button,
|
Button,
|
||||||
|
Divider,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
//import { pool_address } from "@certusone/wormhole-sdk/lib/solana/migration/wormhole_migration";
|
//import { pool_address } from "@certusone/wormhole-sdk/lib/solana/migration/wormhole_migration";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
@ -24,6 +25,19 @@ import getPoolAddress from "@certusone/wormhole-sdk/lib/migration/poolAddress";
|
||||||
import getFromCustodyAddress from "@certusone/wormhole-sdk/lib/migration/fromCustodyAddress";
|
import getFromCustodyAddress from "@certusone/wormhole-sdk/lib/migration/fromCustodyAddress";
|
||||||
import getToCustodyAddress from "@certusone/wormhole-sdk/lib/migration/toCustodyAddress";
|
import getToCustodyAddress from "@certusone/wormhole-sdk/lib/migration/toCustodyAddress";
|
||||||
import getShareMintAddress from "@certusone/wormhole-sdk/lib/migration/shareMintAddress";
|
import getShareMintAddress from "@certusone/wormhole-sdk/lib/migration/shareMintAddress";
|
||||||
|
import parsePool from "@certusone/wormhole-sdk/lib/migration/parsePool";
|
||||||
|
import addLiquidityTx from "@certusone/wormhole-sdk/lib/migration/addLiquidity";
|
||||||
|
import claimSharesTx from "@certusone/wormhole-sdk/lib/migration/claimShares";
|
||||||
|
import migrateTokensTx from "@certusone/wormhole-sdk/lib/migration/migrateTokens";
|
||||||
|
|
||||||
|
import SolanaCreateAssociatedAddress, {
|
||||||
|
useAssociatedAccountExistsState,
|
||||||
|
} from "../components/SolanaCreateAssociatedAddress";
|
||||||
|
import {
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
Token,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
} from "@solana/spl-token";
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles(() => ({
|
||||||
rootContainer: {},
|
rootContainer: {},
|
||||||
|
@ -33,6 +47,9 @@ const useStyles = makeStyles(() => ({
|
||||||
},
|
},
|
||||||
padding: "2rem",
|
padding: "2rem",
|
||||||
},
|
},
|
||||||
|
divider: {
|
||||||
|
margin: "2rem",
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function Main() {
|
function Main() {
|
||||||
|
@ -43,20 +60,56 @@ function Main() {
|
||||||
|
|
||||||
const [fromMint, setFromMint] = useState("");
|
const [fromMint, setFromMint] = useState("");
|
||||||
const [toMint, setToMint] = useState("");
|
const [toMint, setToMint] = useState("");
|
||||||
|
const [shareMintAddress, setShareMintAddress] = useState<string | undefined>(
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
|
||||||
const [poolAddress, setPoolAddress] = useState("");
|
const [poolAddress, setPoolAddress] = useState("");
|
||||||
const [poolExists, setPoolExists] = useState<boolean | null>(null);
|
const [poolExists, setPoolExists] = useState<boolean | undefined>(undefined);
|
||||||
const [poolAccountInfo, setPoolAccountInfo] = useState(null);
|
const [poolAccountInfo, setPoolAccountInfo] = useState(undefined);
|
||||||
const [shareTokenMint, setShareTokenMint] = useState(null);
|
const [parsedPoolData, setParsedPoolData] = useState(undefined);
|
||||||
const [toTokenAccount, setToTokenAccount] = useState(null);
|
|
||||||
const [fromTokenAccount, setFromTokenAccount] = useState(null);
|
//These are the user's personal token accounts corresponding to the mints for the connected wallet
|
||||||
const [shareTokenAccount, setShareTokenAccount] = useState(null);
|
const [fromTokenAccount, setFromTokenAccount] = useState<string | undefined>(
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
const [toTokenAccount, setToTokenAccount] = useState<string | undefined>(
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
const [shareTokenAccount, setShareTokenAccount] = useState<
|
||||||
|
string | undefined
|
||||||
|
>(undefined);
|
||||||
|
|
||||||
|
//These hooks detect if the connected wallet has the requisite token accounts
|
||||||
|
const {
|
||||||
|
associatedAccountExists: fromTokenAccountExists,
|
||||||
|
setAssociatedAccountExists: setFromTokenAccountExists,
|
||||||
|
} = useAssociatedAccountExistsState(fromMint, fromTokenAccount);
|
||||||
|
const {
|
||||||
|
associatedAccountExists: toTokenAccountExists,
|
||||||
|
setAssociatedAccountExists: setToTokenAccountExists,
|
||||||
|
} = useAssociatedAccountExistsState(toMint, toTokenAccount);
|
||||||
|
const {
|
||||||
|
associatedAccountExists: shareTokenAccountExists,
|
||||||
|
setAssociatedAccountExists: setShareTokenAccountExists,
|
||||||
|
} = useAssociatedAccountExistsState(shareMintAddress, shareTokenAccount);
|
||||||
|
|
||||||
//these are all the other derived information
|
//these are all the other derived information
|
||||||
const [authorityAddress, setAuthorityAddress] = useState(null);
|
const [authorityAddress, setAuthorityAddress] = useState<string | undefined>(
|
||||||
const [fromCustodyAddress, setFromCustodyAddress] = useState(null);
|
undefined
|
||||||
const [toCustodyAddress, setToCustodyAddress] = useState(null);
|
);
|
||||||
const [shareMintAddress, setShareMintAddress] = useState(null);
|
const [fromCustodyAddress, setFromCustodyAddress] = useState<
|
||||||
|
string | undefined
|
||||||
|
>(undefined);
|
||||||
|
const [toCustodyAddress, setToCustodyAddress] = useState<string | undefined>(
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
const [toggleAllData, setToggleAllData] = useState(false);
|
||||||
|
|
||||||
|
const [liquidityAmount, setLiquidityAmount] = useState("");
|
||||||
|
const [migrationAmount, setMigrationAmount] = useState("");
|
||||||
|
const [redeemAmount, setRedeemAmount] = useState("");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Effects***
|
Effects***
|
||||||
|
@ -82,8 +135,8 @@ function Main() {
|
||||||
//Retrieve the poolAccount every time the pool address changes.
|
//Retrieve the poolAccount every time the pool address changes.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (poolAddress) {
|
if (poolAddress) {
|
||||||
setPoolAccountInfo(null);
|
setPoolAccountInfo(undefined);
|
||||||
setPoolExists(null);
|
setPoolExists(undefined);
|
||||||
try {
|
try {
|
||||||
getMultipleAccounts(
|
getMultipleAccounts(
|
||||||
connection,
|
connection,
|
||||||
|
@ -92,6 +145,13 @@ function Main() {
|
||||||
).then((result) => {
|
).then((result) => {
|
||||||
if (result.length && result[0] !== null) {
|
if (result.length && result[0] !== null) {
|
||||||
setPoolAccountInfo(result[0]);
|
setPoolAccountInfo(result[0]);
|
||||||
|
parsePool(result[0].data).then(
|
||||||
|
(parsed) => setParsedPoolData(parsed),
|
||||||
|
(error) => {
|
||||||
|
logger.log("Failed to parse the pool data.");
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
setPoolExists(true);
|
setPoolExists(true);
|
||||||
logger.log("Successfully found account info for the pool.");
|
logger.log("Successfully found account info for the pool.");
|
||||||
} else if (result.length && result[0] === null) {
|
} else if (result.length && result[0] === null) {
|
||||||
|
@ -109,21 +169,71 @@ function Main() {
|
||||||
}
|
}
|
||||||
}, [poolAddress]);
|
}, [poolAddress]);
|
||||||
|
|
||||||
|
//Set all the addresses which derive from poolAddress
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getAuthorityAddress(MIGRATION_PROGRAM_ADDRESS).then((result: any) =>
|
getAuthorityAddress(MIGRATION_PROGRAM_ADDRESS).then((result: any) =>
|
||||||
setAuthorityAddress(result)
|
setAuthorityAddress(new PublicKey(result).toString())
|
||||||
);
|
);
|
||||||
|
|
||||||
getToCustodyAddress(MIGRATION_PROGRAM_ADDRESS, poolAddress).then(
|
getToCustodyAddress(MIGRATION_PROGRAM_ADDRESS, poolAddress).then(
|
||||||
(result: any) => setToCustodyAddress(result)
|
(result: any) => setToCustodyAddress(new PublicKey(result).toString())
|
||||||
);
|
);
|
||||||
getFromCustodyAddress(MIGRATION_PROGRAM_ADDRESS, poolAddress).then(
|
getFromCustodyAddress(MIGRATION_PROGRAM_ADDRESS, poolAddress).then(
|
||||||
(result: any) => setFromCustodyAddress(result)
|
(result: any) => setFromCustodyAddress(new PublicKey(result).toString())
|
||||||
);
|
);
|
||||||
getShareMintAddress(MIGRATION_PROGRAM_ADDRESS, poolAddress).then(
|
getShareMintAddress(MIGRATION_PROGRAM_ADDRESS, poolAddress).then(
|
||||||
(result: any) => setShareMintAddress(result)
|
(result: any) => setShareMintAddress(new PublicKey(result).toString())
|
||||||
);
|
);
|
||||||
}, [poolAddress]);
|
}, [poolAddress]);
|
||||||
|
|
||||||
|
//Set the associated token accounts when the designated mint changes
|
||||||
|
useEffect(() => {
|
||||||
|
if (wallet?.publicKey && fromMint) {
|
||||||
|
Token.getAssociatedTokenAddress(
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
new PublicKey(fromMint),
|
||||||
|
wallet?.publicKey || new PublicKey([])
|
||||||
|
).then(
|
||||||
|
(result) => {
|
||||||
|
setFromTokenAccount(result.toString());
|
||||||
|
},
|
||||||
|
(error) => {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [fromMint, wallet?.publicKey]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (wallet?.publicKey && toMint) {
|
||||||
|
Token.getAssociatedTokenAddress(
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
new PublicKey(toMint),
|
||||||
|
wallet?.publicKey || new PublicKey([])
|
||||||
|
).then(
|
||||||
|
(result) => {
|
||||||
|
setToTokenAccount(result.toString());
|
||||||
|
},
|
||||||
|
(error) => {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [toMint, wallet?.publicKey]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (wallet?.publicKey && shareMintAddress) {
|
||||||
|
Token.getAssociatedTokenAddress(
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
new PublicKey(shareMintAddress || ""),
|
||||||
|
wallet?.publicKey || new PublicKey([])
|
||||||
|
).then(
|
||||||
|
(result) => {
|
||||||
|
setShareTokenAccount(result.toString());
|
||||||
|
},
|
||||||
|
(error) => {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [shareMintAddress, wallet?.publicKey]);
|
||||||
/*
|
/*
|
||||||
End Effects!
|
End Effects!
|
||||||
*/
|
*/
|
||||||
|
@ -136,6 +246,14 @@ function Main() {
|
||||||
|
|
||||||
*/
|
*/
|
||||||
const createPool = async () => {
|
const createPool = async () => {
|
||||||
|
console.log(
|
||||||
|
"createPool with these args",
|
||||||
|
connection,
|
||||||
|
wallet?.publicKey?.toString(),
|
||||||
|
MIGRATION_PROGRAM_ADDRESS,
|
||||||
|
fromMint,
|
||||||
|
toMint
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
const instruction = await createPoolAccount(
|
const instruction = await createPoolAccount(
|
||||||
connection,
|
connection,
|
||||||
|
@ -148,8 +266,8 @@ function Main() {
|
||||||
|
|
||||||
signSendAndConfirm(wallet, connection, instruction).then(
|
signSendAndConfirm(wallet, connection, instruction).then(
|
||||||
(transaction: any) => {
|
(transaction: any) => {
|
||||||
setPoolExists(null); //Set these to null to force a fetch on them
|
setPoolExists(undefined); //Set these to null to force a fetch on them
|
||||||
setPoolAccountInfo(null);
|
setPoolAccountInfo(undefined);
|
||||||
logger.log("Successfully created the pool.");
|
logger.log("Successfully created the pool.");
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
@ -162,6 +280,96 @@ function Main() {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const addLiquidity = async () => {
|
||||||
|
try {
|
||||||
|
const instruction = await addLiquidityTx(
|
||||||
|
connection,
|
||||||
|
wallet?.publicKey?.toString() || "",
|
||||||
|
MIGRATION_PROGRAM_ADDRESS,
|
||||||
|
fromMint,
|
||||||
|
toMint,
|
||||||
|
toTokenAccount || "",
|
||||||
|
shareTokenAccount || "",
|
||||||
|
BigInt(liquidityAmount)
|
||||||
|
);
|
||||||
|
|
||||||
|
signSendAndConfirm(wallet, connection, instruction).then(
|
||||||
|
(transaction: any) => {
|
||||||
|
setPoolExists(undefined); //Set these to null to force a fetch on them
|
||||||
|
setPoolAccountInfo(undefined);
|
||||||
|
logger.log("Successfully added liquidity to the pool.");
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
logger.log("Could not complete the addLiquidity transaction");
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
logger.log("Could not complete the addLiquidity transaction");
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const migrateTokens = async () => {
|
||||||
|
try {
|
||||||
|
const instruction = await migrateTokensTx(
|
||||||
|
connection,
|
||||||
|
wallet?.publicKey?.toString() || "",
|
||||||
|
MIGRATION_PROGRAM_ADDRESS,
|
||||||
|
fromMint,
|
||||||
|
toMint,
|
||||||
|
fromTokenAccount || "",
|
||||||
|
toTokenAccount || "",
|
||||||
|
BigInt(migrationAmount)
|
||||||
|
);
|
||||||
|
|
||||||
|
signSendAndConfirm(wallet, connection, instruction).then(
|
||||||
|
(transaction: any) => {
|
||||||
|
setPoolExists(undefined); //Set these to null to force a fetch on them
|
||||||
|
setPoolAccountInfo(undefined);
|
||||||
|
logger.log("Successfully migrated the tokens.");
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
logger.log("Could not complete the migrateTokens transaction.");
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
logger.log("Could not complete the migrateTokens transaction.");
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const redeemShares = async () => {
|
||||||
|
try {
|
||||||
|
const instruction = await claimSharesTx(
|
||||||
|
connection,
|
||||||
|
wallet?.publicKey?.toString() || "",
|
||||||
|
MIGRATION_PROGRAM_ADDRESS,
|
||||||
|
fromMint,
|
||||||
|
toMint,
|
||||||
|
toTokenAccount || "",
|
||||||
|
shareTokenAccount || "",
|
||||||
|
BigInt(redeemAmount)
|
||||||
|
);
|
||||||
|
|
||||||
|
signSendAndConfirm(wallet, connection, instruction).then(
|
||||||
|
(transaction: any) => {
|
||||||
|
setPoolExists(undefined); //Set these to null to force a fetch on them
|
||||||
|
setPoolAccountInfo(undefined);
|
||||||
|
logger.log("Successfully redeemed the shares.");
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
logger.log("Could not complete the claimShares transaction.");
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
logger.log("Could not complete the claimShares transaction.");
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
/*
|
/*
|
||||||
End actions!
|
End actions!
|
||||||
*/
|
*/
|
||||||
|
@ -194,35 +402,156 @@ function Main() {
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() => createPool()}
|
onClick={() => createPool()}
|
||||||
disabled={poolExists || !poolAddress}
|
disabled={poolExists}
|
||||||
>
|
>
|
||||||
Click here to instantiate the pool for these tokens.
|
{poolExists
|
||||||
|
? "This Pool is instantiated."
|
||||||
|
: "This pool has not been instantiated! Click here to create it."}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const addLiquidity = (
|
const addLiquidityUI = (
|
||||||
<>
|
<>
|
||||||
<Typography>
|
<Typography variant="h4">Add Liquidity</Typography>
|
||||||
Add 'to' tokens to this pool, and receive liquidity tokens.
|
<Typography variant="body1">
|
||||||
|
This will remove 'To' tokens from your wallet, and give you an equal
|
||||||
|
number of 'Share' tokens.
|
||||||
</Typography>
|
</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
value={toMint}
|
value={liquidityAmount}
|
||||||
onChange={(event) => setToMint(event.target.value)}
|
type="number"
|
||||||
label={"To Token"}
|
onChange={(event) => setLiquidityAmount(event.target.value)}
|
||||||
|
label={"Amount to add"}
|
||||||
></TextField>
|
></TextField>
|
||||||
|
<Button variant="contained" onClick={addLiquidity}>
|
||||||
|
Add Liquidity
|
||||||
|
</Button>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const migrateTokensUI = (
|
||||||
|
<>
|
||||||
|
<Typography variant="h4">Migrate Tokens</Typography>
|
||||||
|
<Typography variant="body1">
|
||||||
|
This will remove 'From' tokens from your wallet, and give you an equal
|
||||||
|
number of 'To' tokens.
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
value={migrationAmount}
|
||||||
|
type="number"
|
||||||
|
onChange={(event) => setMigrationAmount(event.target.value)}
|
||||||
|
label={"Amount to add"}
|
||||||
|
></TextField>
|
||||||
|
<Button variant="contained" onClick={migrateTokens}>
|
||||||
|
Migrate Tokens
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
const redeemSharesUI = (
|
||||||
|
<>
|
||||||
|
<Typography variant="h4">Redeem Shares</Typography>
|
||||||
|
<Typography variant="body1">
|
||||||
|
This will remove 'Share' tokens from your wallet, and give you an equal
|
||||||
|
number of 'From' tokens.
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
type="number"
|
||||||
|
value={redeemAmount}
|
||||||
|
onChange={(event) => setRedeemAmount(event.target.value)}
|
||||||
|
label={"Amount to add"}
|
||||||
|
></TextField>
|
||||||
|
<Button variant="contained" onClick={redeemShares}>
|
||||||
|
Redeem Shares
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
const relevantTokenAccounts = (
|
||||||
|
<>
|
||||||
|
<Typography variant="h4">Your Relevant Token Accounts: </Typography>
|
||||||
|
<Typography variant="body1">
|
||||||
|
{"'From' SPL Token Account: " + fromTokenAccount}
|
||||||
|
</Typography>
|
||||||
|
<SolanaCreateAssociatedAddress
|
||||||
|
mintAddress={fromMint}
|
||||||
|
readableTargetAddress={fromTokenAccount}
|
||||||
|
associatedAccountExists={fromTokenAccountExists}
|
||||||
|
setAssociatedAccountExists={setFromTokenAccountExists}
|
||||||
|
/>
|
||||||
|
<Typography variant="body1">
|
||||||
|
{"'To' SPL Token Account: " + toTokenAccount}
|
||||||
|
</Typography>
|
||||||
|
<SolanaCreateAssociatedAddress
|
||||||
|
mintAddress={toMint}
|
||||||
|
readableTargetAddress={toTokenAccount}
|
||||||
|
associatedAccountExists={toTokenAccountExists}
|
||||||
|
setAssociatedAccountExists={setToTokenAccountExists}
|
||||||
|
/>
|
||||||
|
<Typography variant="body1">
|
||||||
|
{"Share SPL Token Account: " + shareTokenAccount}
|
||||||
|
</Typography>
|
||||||
|
<SolanaCreateAssociatedAddress
|
||||||
|
mintAddress={shareMintAddress}
|
||||||
|
readableTargetAddress={shareTokenAccount}
|
||||||
|
associatedAccountExists={shareTokenAccountExists}
|
||||||
|
setAssociatedAccountExists={setShareTokenAccountExists}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
const poolInfo = (
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => setToggleAllData(!toggleAllData)}
|
||||||
|
>
|
||||||
|
{toggleAllData ? "Hide Verbose Pool Data" : "Show Verbose Pool Data"}
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
{toggleAllData ? (
|
||||||
|
<>
|
||||||
|
<Typography>{"Pool Address: " + poolAddress}</Typography>
|
||||||
|
<Typography>{"Pool has been instantiated: " + poolExists}</Typography>
|
||||||
|
<Typography>{"'From' Token Mint Address: " + fromMint}</Typography>
|
||||||
|
<Typography>{"'To' Token Mint Address: " + toMint}</Typography>
|
||||||
|
<Typography>{"Share Token Mint: " + shareMintAddress}</Typography>
|
||||||
|
<Typography>{"Authority Address: " + authorityAddress}</Typography>
|
||||||
|
<Typography>
|
||||||
|
{"'From' Custody Mint: " + fromCustodyAddress}
|
||||||
|
</Typography>
|
||||||
|
<Typography>{"'To' Custody Mint: " + toCustodyAddress}</Typography>
|
||||||
|
<Typography>
|
||||||
|
{"Full Parsed Data for Pool: " + JSON.stringify(parsedPoolData)}
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
const mainContent = (
|
const mainContent = (
|
||||||
<>
|
<>
|
||||||
{toAndFromSelector}
|
{toAndFromSelector}
|
||||||
|
<Divider className={classes.divider} />
|
||||||
|
{poolInfo}
|
||||||
{createPoolButton}
|
{createPoolButton}
|
||||||
|
<Divider className={classes.divider} />
|
||||||
|
{relevantTokenAccounts}
|
||||||
|
<Divider className={classes.divider} />
|
||||||
|
{addLiquidityUI}
|
||||||
|
<Divider className={classes.divider} />
|
||||||
|
{redeemSharesUI}
|
||||||
|
<Divider className={classes.divider} />
|
||||||
|
{migrateTokensUI}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
const content = !wallet.publicKey ? (
|
const content = !wallet.publicKey ? (
|
||||||
<Typography>Please connect your wallet.</Typography>
|
<Typography>Please connect your wallet.</Typography>
|
||||||
|
) : !poolAddress ? (
|
||||||
|
toAndFromSelector
|
||||||
) : (
|
) : (
|
||||||
mainContent
|
mainContent
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue