Add a button to delete token accounts
This commit is contained in:
parent
ee8018c6fd
commit
02b4748fb5
|
@ -21,6 +21,7 @@ import { abbreviateAddress } from '../utils/utils';
|
|||
import Button from '@material-ui/core/Button';
|
||||
import SendIcon from '@material-ui/icons/Send';
|
||||
import ReceiveIcon from '@material-ui/icons/WorkOutline';
|
||||
import DeleteIcon from '@material-ui/icons/Delete';
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import Toolbar from '@material-ui/core/Toolbar';
|
||||
import AddIcon from '@material-ui/icons/Add';
|
||||
|
@ -36,6 +37,7 @@ import {
|
|||
useSolanaExplorerUrlSuffix,
|
||||
} from '../utils/connection';
|
||||
import { showTokenInfoDialog } from '../utils/config';
|
||||
import CloseTokenAccountDialog from './CloseTokenAccountButton';
|
||||
|
||||
const balanceFormat = new Intl.NumberFormat(undefined, {
|
||||
minimumFractionDigits: 4,
|
||||
|
@ -150,12 +152,16 @@ function BalanceListItemDetails({ publicKey, balanceInfo }) {
|
|||
const [sendDialogOpen, setSendDialogOpen] = useState(false);
|
||||
const [depositDialogOpen, setDepositDialogOpen] = useState(false);
|
||||
const [tokenInfoDialogOpen, setTokenInfoDialogOpen] = useState(false);
|
||||
const [
|
||||
closeTokenAccountDialogOpen,
|
||||
setCloseTokenAccountDialogOpen,
|
||||
] = useState(false);
|
||||
|
||||
if (!balanceInfo) {
|
||||
return <LoadingIndicator delay={0} />;
|
||||
}
|
||||
|
||||
let { mint, tokenName, tokenSymbol, owner } = balanceInfo;
|
||||
let { mint, tokenName, tokenSymbol, owner, amount } = balanceInfo;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -187,6 +193,17 @@ function BalanceListItemDetails({ publicKey, balanceInfo }) {
|
|||
>
|
||||
Send
|
||||
</Button>
|
||||
{mint && amount === 0 ? (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
size="small"
|
||||
startIcon={<DeleteIcon />}
|
||||
onClick={() => setCloseTokenAccountDialogOpen(true)}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
<Typography variant="body2" className={classes.address}>
|
||||
Deposit Address: {publicKey.toBase58()}
|
||||
|
@ -233,6 +250,12 @@ function BalanceListItemDetails({ publicKey, balanceInfo }) {
|
|||
balanceInfo={balanceInfo}
|
||||
publicKey={publicKey}
|
||||
/>
|
||||
<CloseTokenAccountDialog
|
||||
open={closeTokenAccountDialogOpen}
|
||||
onClose={() => setCloseTokenAccountDialogOpen(false)}
|
||||
balanceInfo={balanceInfo}
|
||||
publicKey={publicKey}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
import DialogForm from './DialogForm';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import { DialogContentText } from '@material-ui/core';
|
||||
import { abbreviateAddress } from '../utils/utils';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import React from 'react';
|
||||
import { useSendTransaction } from '../utils/notifications';
|
||||
import { refreshWalletPublicKeys, useWallet } from '../utils/wallet';
|
||||
|
||||
export default function CloseTokenAccountDialog({
|
||||
open,
|
||||
onClose,
|
||||
publicKey,
|
||||
balanceInfo,
|
||||
}) {
|
||||
const wallet = useWallet();
|
||||
const [sendTransaction, sending] = useSendTransaction();
|
||||
const { mint, tokenName } = balanceInfo;
|
||||
|
||||
function onSubmit() {
|
||||
sendTransaction(wallet.closeTokenAccount(publicKey), {
|
||||
onSuccess: () => {
|
||||
refreshWalletPublicKeys(wallet);
|
||||
onClose();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<DialogForm open={open} onClose={onClose} onSubmit={onSubmit}>
|
||||
<DialogTitle>
|
||||
Delete {tokenName ?? mint.toBase58()} Address{' '}
|
||||
{abbreviateAddress(publicKey)}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
Are you sure you want to delete your {tokenName ?? mint.toBase58()}{' '}
|
||||
address {publicKey.toBase58()}? This will permanently disable token
|
||||
transfers to this address and remove it from your wallet.
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onClose}>Cancel</Button>
|
||||
<Button type="submit" color="secondary" disabled={sending}>
|
||||
Delete
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</DialogForm>
|
||||
);
|
||||
}
|
|
@ -59,13 +59,15 @@ export function useAccountInfo(publicKey) {
|
|||
if (!publicKey) {
|
||||
return;
|
||||
}
|
||||
let previousData = null;
|
||||
let previousInfo = null;
|
||||
const id = connection.onAccountChange(publicKey, (info) => {
|
||||
if (info.data) {
|
||||
if (!previousData || !previousData.equals(info.data)) {
|
||||
previousData = info.data;
|
||||
setCache(cacheKey, info);
|
||||
}
|
||||
if (
|
||||
!previousInfo ||
|
||||
!previousInfo.data.equals(info.data) ||
|
||||
previousInfo.lamports !== info.lamports
|
||||
) {
|
||||
previousInfo = info;
|
||||
setCache(cacheKey, info);
|
||||
}
|
||||
});
|
||||
return () => connection.removeAccountChangeListener(id);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { PublicKey, SystemProgram, Transaction } from '@solana/web3.js';
|
||||
import {
|
||||
closeAccount,
|
||||
initializeAccount,
|
||||
initializeMint,
|
||||
memoInstruction,
|
||||
|
@ -173,3 +174,21 @@ export async function transferTokens({
|
|||
preflightCommitment: 'single',
|
||||
});
|
||||
}
|
||||
|
||||
export async function closeTokenAccount({
|
||||
connection,
|
||||
owner,
|
||||
sourcePublicKey,
|
||||
}) {
|
||||
let transaction = new Transaction().add(
|
||||
closeAccount({
|
||||
source: sourcePublicKey,
|
||||
destination: owner.publicKey,
|
||||
owner: owner.publicKey,
|
||||
}),
|
||||
);
|
||||
let signers = [owner];
|
||||
return await connection.sendTransaction(transaction, signers, {
|
||||
preflightCommitment: 'single',
|
||||
});
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ LAYOUT.addVariant(
|
|||
BufferLayout.struct([BufferLayout.nu64('amount')]),
|
||||
'burn',
|
||||
);
|
||||
LAYOUT.addVariant(9, BufferLayout.struct([]), 'closeAccount');
|
||||
|
||||
const instructionMaxSpan = Math.max(
|
||||
...Object.values(LAYOUT.registry).map((r) => r.span),
|
||||
|
@ -127,6 +128,21 @@ export function mintTo({ mint, destination, amount, mintAuthority }) {
|
|||
});
|
||||
}
|
||||
|
||||
export function closeAccount({ source, destination, owner }) {
|
||||
const keys = [
|
||||
{ pubkey: source, isSigner: false, isWritable: true },
|
||||
{ pubkey: destination, isSigner: false, isWritable: true },
|
||||
{ pubkey: owner, isSigner: true, isWritable: false },
|
||||
];
|
||||
return new TransactionInstruction({
|
||||
keys,
|
||||
data: encodeTokenInstructionData({
|
||||
closeAccount: {},
|
||||
}),
|
||||
programId: TOKEN_PROGRAM_ID,
|
||||
});
|
||||
}
|
||||
|
||||
export function memoInstruction(memo) {
|
||||
return new TransactionInstruction({
|
||||
keys: [],
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
useConnection,
|
||||
} from './connection';
|
||||
import {
|
||||
closeTokenAccount,
|
||||
createAndInitializeTokenAccount,
|
||||
getOwnedTokenAccounts,
|
||||
transferTokens,
|
||||
|
@ -97,6 +98,14 @@ export class Wallet {
|
|||
preflightCommitment: 'single',
|
||||
});
|
||||
};
|
||||
|
||||
closeTokenAccount = async (publicKey) => {
|
||||
return await closeTokenAccount({
|
||||
connection: this.connection,
|
||||
owner: this.account,
|
||||
sourcePublicKey: publicKey,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const WalletContext = React.createContext(null);
|
||||
|
|
Loading…
Reference in New Issue