diff --git a/bridge_ui/src/components/SmartAddress.tsx b/bridge_ui/src/components/SmartAddress.tsx
index cd858597b..3e61fe397 100644
--- a/bridge_ui/src/components/SmartAddress.tsx
+++ b/bridge_ui/src/components/SmartAddress.tsx
@@ -9,6 +9,7 @@ import { Button, makeStyles, Tooltip, Typography } from "@material-ui/core";
import { FileCopy, OpenInNew } from "@material-ui/icons";
import { withStyles } from "@material-ui/styles";
import clsx from "clsx";
+import { ReactChild } from "react";
import useCopyToClipboard from "../hooks/useCopyToClipboard";
import { ParsedTokenAccount } from "../store/transferSlice";
import { CLUSTER, getExplorerName } from "../utils/consts";
@@ -57,6 +58,7 @@ export default function SmartAddress({
variant,
noGutter,
noUnderline,
+ extraContent,
}: {
chainId: ChainId;
parsedTokenAccount?: ParsedTokenAccount;
@@ -67,6 +69,7 @@ export default function SmartAddress({
variant?: any;
noGutter?: boolean;
noUnderline?: boolean;
+ extraContent?: ReactChild;
}) {
const classes = useStyles();
const useableAddress = parsedTokenAccount?.mintKey || address || "";
@@ -148,6 +151,7 @@ export default function SmartAddress({
{explorerButton}
{copyButton}
+ {extraContent ? extraContent : null}
>
);
diff --git a/bridge_ui/src/components/SolanaCreateAssociatedAddress.tsx b/bridge_ui/src/components/SolanaCreateAssociatedAddress.tsx
index 455b2fe73..6fe8eb5a4 100644
--- a/bridge_ui/src/components/SolanaCreateAssociatedAddress.tsx
+++ b/bridge_ui/src/components/SolanaCreateAssociatedAddress.tsx
@@ -5,13 +5,15 @@ import {
hexToNativeString,
hexToUint8Array,
} from "@certusone/wormhole-sdk";
-import { Typography } from "@material-ui/core";
+import { Button, Typography } from "@material-ui/core";
+import { Alert } from "@material-ui/lab";
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
Token,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
import { Connection, PublicKey, Transaction } from "@solana/web3.js";
+import { useSnackbar } from "notistack";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useSelector } from "react-redux";
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
@@ -21,6 +23,7 @@ import {
selectTransferTargetAddressHex,
} from "../store/selectors";
import { SOLANA_HOST, SOL_TOKEN_BRIDGE_ADDRESS } from "../utils/consts";
+import parseError from "../utils/parseError";
import { signSendAndConfirm } from "../utils/solana";
import ButtonWithLoader from "./ButtonWithLoader";
import SmartAddress from "./SmartAddress";
@@ -163,6 +166,7 @@ export default function SolanaCreateAssociatedAddress({
}
export function SolanaCreateAssociatedAddressAlternate() {
+ const { enqueueSnackbar } = useSnackbar();
const originChain = useSelector(selectTransferOriginChain);
const originAsset = useSelector(selectTransferOriginAsset);
const addressHex = useSelector(selectTransferTargetAddressHex);
@@ -215,7 +219,62 @@ export function SolanaCreateAssociatedAddressAlternate() {
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: (
+