bridge_ui: allow force create account on redeem
Change-Id: I6f01fd350dd18339ba0b5659ab43bd5c2a2a22c7
This commit is contained in:
parent
fb030b3351
commit
9bc408ca19
|
@ -9,6 +9,7 @@ import { Button, makeStyles, Tooltip, Typography } from "@material-ui/core";
|
||||||
import { FileCopy, OpenInNew } from "@material-ui/icons";
|
import { FileCopy, OpenInNew } from "@material-ui/icons";
|
||||||
import { withStyles } from "@material-ui/styles";
|
import { withStyles } from "@material-ui/styles";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
import { ReactChild } from "react";
|
||||||
import useCopyToClipboard from "../hooks/useCopyToClipboard";
|
import useCopyToClipboard from "../hooks/useCopyToClipboard";
|
||||||
import { ParsedTokenAccount } from "../store/transferSlice";
|
import { ParsedTokenAccount } from "../store/transferSlice";
|
||||||
import { CLUSTER, getExplorerName } from "../utils/consts";
|
import { CLUSTER, getExplorerName } from "../utils/consts";
|
||||||
|
@ -57,6 +58,7 @@ export default function SmartAddress({
|
||||||
variant,
|
variant,
|
||||||
noGutter,
|
noGutter,
|
||||||
noUnderline,
|
noUnderline,
|
||||||
|
extraContent,
|
||||||
}: {
|
}: {
|
||||||
chainId: ChainId;
|
chainId: ChainId;
|
||||||
parsedTokenAccount?: ParsedTokenAccount;
|
parsedTokenAccount?: ParsedTokenAccount;
|
||||||
|
@ -67,6 +69,7 @@ export default function SmartAddress({
|
||||||
variant?: any;
|
variant?: any;
|
||||||
noGutter?: boolean;
|
noGutter?: boolean;
|
||||||
noUnderline?: boolean;
|
noUnderline?: boolean;
|
||||||
|
extraContent?: ReactChild;
|
||||||
}) {
|
}) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const useableAddress = parsedTokenAccount?.mintKey || address || "";
|
const useableAddress = parsedTokenAccount?.mintKey || address || "";
|
||||||
|
@ -148,6 +151,7 @@ export default function SmartAddress({
|
||||||
{explorerButton}
|
{explorerButton}
|
||||||
{copyButton}
|
{copyButton}
|
||||||
</div>
|
</div>
|
||||||
|
{extraContent ? extraContent : null}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,15 @@ import {
|
||||||
hexToNativeString,
|
hexToNativeString,
|
||||||
hexToUint8Array,
|
hexToUint8Array,
|
||||||
} from "@certusone/wormhole-sdk";
|
} from "@certusone/wormhole-sdk";
|
||||||
import { Typography } from "@material-ui/core";
|
import { Button, Typography } from "@material-ui/core";
|
||||||
|
import { Alert } from "@material-ui/lab";
|
||||||
import {
|
import {
|
||||||
ASSOCIATED_TOKEN_PROGRAM_ID,
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
Token,
|
Token,
|
||||||
TOKEN_PROGRAM_ID,
|
TOKEN_PROGRAM_ID,
|
||||||
} from "@solana/spl-token";
|
} from "@solana/spl-token";
|
||||||
import { Connection, PublicKey, Transaction } from "@solana/web3.js";
|
import { Connection, PublicKey, Transaction } from "@solana/web3.js";
|
||||||
|
import { useSnackbar } from "notistack";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
||||||
|
@ -21,6 +23,7 @@ import {
|
||||||
selectTransferTargetAddressHex,
|
selectTransferTargetAddressHex,
|
||||||
} from "../store/selectors";
|
} from "../store/selectors";
|
||||||
import { SOLANA_HOST, SOL_TOKEN_BRIDGE_ADDRESS } from "../utils/consts";
|
import { SOLANA_HOST, SOL_TOKEN_BRIDGE_ADDRESS } from "../utils/consts";
|
||||||
|
import parseError from "../utils/parseError";
|
||||||
import { signSendAndConfirm } from "../utils/solana";
|
import { signSendAndConfirm } from "../utils/solana";
|
||||||
import ButtonWithLoader from "./ButtonWithLoader";
|
import ButtonWithLoader from "./ButtonWithLoader";
|
||||||
import SmartAddress from "./SmartAddress";
|
import SmartAddress from "./SmartAddress";
|
||||||
|
@ -163,6 +166,7 @@ export default function SolanaCreateAssociatedAddress({
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SolanaCreateAssociatedAddressAlternate() {
|
export function SolanaCreateAssociatedAddressAlternate() {
|
||||||
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
const originChain = useSelector(selectTransferOriginChain);
|
const originChain = useSelector(selectTransferOriginChain);
|
||||||
const originAsset = useSelector(selectTransferOriginAsset);
|
const originAsset = useSelector(selectTransferOriginAsset);
|
||||||
const addressHex = useSelector(selectTransferTargetAddressHex);
|
const addressHex = useSelector(selectTransferTargetAddressHex);
|
||||||
|
@ -215,7 +219,62 @@ export function SolanaCreateAssociatedAddressAlternate() {
|
||||||
base58TargetAddress
|
base58TargetAddress
|
||||||
);
|
);
|
||||||
|
|
||||||
return targetAsset && !associatedAccountExists ? (
|
const solanaWallet = useSolanaWallet();
|
||||||
|
const solPK = solanaWallet?.publicKey;
|
||||||
|
const handleForceCreateClick = useCallback(() => {
|
||||||
|
if (!targetAsset || !base58TargetAddress || !solPK) return;
|
||||||
|
(async () => {
|
||||||
|
const connection = new Connection(SOLANA_HOST, "confirmed");
|
||||||
|
const mintPublicKey = new PublicKey(targetAsset);
|
||||||
|
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() === base58TargetAddress;
|
||||||
|
if (match) {
|
||||||
|
try {
|
||||||
|
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);
|
||||||
|
setAssociatedAccountExists(true);
|
||||||
|
enqueueSnackbar(null, {
|
||||||
|
content: (
|
||||||
|
<Alert severity="success">
|
||||||
|
Successfully created associated token account
|
||||||
|
</Alert>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
enqueueSnackbar(null, {
|
||||||
|
content: <Alert severity="error">{parseError(e)}</Alert>,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, [
|
||||||
|
setAssociatedAccountExists,
|
||||||
|
targetAsset,
|
||||||
|
solPK,
|
||||||
|
base58TargetAddress,
|
||||||
|
solanaWallet,
|
||||||
|
enqueueSnackbar,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return targetAsset ? (
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<Typography variant="subtitle2">Recipient Address:</Typography>
|
<Typography variant="subtitle2">Recipient Address:</Typography>
|
||||||
<Typography component="div">
|
<Typography component="div">
|
||||||
|
@ -223,15 +282,26 @@ export function SolanaCreateAssociatedAddressAlternate() {
|
||||||
chainId={CHAIN_ID_SOLANA}
|
chainId={CHAIN_ID_SOLANA}
|
||||||
address={base58TargetAddress}
|
address={base58TargetAddress}
|
||||||
variant="h6"
|
variant="h6"
|
||||||
|
extraContent={
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
onClick={handleForceCreateClick}
|
||||||
|
disabled={!targetAsset || !base58TargetAddress || !solPK}
|
||||||
|
>
|
||||||
|
Force Create Account
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{associatedAccountExists ? null : (
|
||||||
<SolanaCreateAssociatedAddress
|
<SolanaCreateAssociatedAddress
|
||||||
mintAddress={targetAsset}
|
mintAddress={targetAsset}
|
||||||
readableTargetAddress={base58TargetAddress}
|
readableTargetAddress={base58TargetAddress}
|
||||||
associatedAccountExists={associatedAccountExists}
|
associatedAccountExists={associatedAccountExists}
|
||||||
setAssociatedAccountExists={setAssociatedAccountExists}
|
setAssociatedAccountExists={setAssociatedAccountExists}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue