---
title: Close Mint
description:
  Create a Token Extension Program mint with the MintCloseAuthority extension,
  then burn the remaining supply and close the mint.
url: /docs/tokens/extensions/close-mint
type: tutorial
prerequisites:
  - /docs/tokens/basics/create-mint
  - /docs/tokens/basics/mint-tokens
  - /docs/tokens/basics/burn-tokens
related:
  - /docs/tokens/basics/close-account
  - /docs/tokens/extensions
---

## What Is Mint Close Authority?

The Token Extension Program's _rs`MintCloseAuthority`_ mint extension lets a
designated authority close a mint account and reclaim its rent once the mint's
total supply reaches zero.

Without this extension, a mint account cannot be closed.

- The total supply must be zero, so all tokens in all token accounts must be
  burned before a mint can be closed
- Only the configured close authority can close the mint

## How to Create and Close a Mint

To create and close a mint:

1. Calculate the mint account size and rent needed for the mint and the
   _rs`MintCloseAuthority`_ extension.
2. Create the mint account with _rs`CreateAccount`_, initialize
   _rs`MintCloseAuthority`_, and initialize the mint with _rs`InitializeMint`_.
3. If the total supply is zero, the mint account can be closed with
   _rs`CloseAccount`_, signed by the close authority.

<ScrollyCoding>

## !!steps Calculate account size

Calculate the mint account size for the base mint plus the
_rs`MintCloseAuthority`_ extension. This is the size used in
_rs`CreateAccount`_.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const destination = await generateKeyPairSigner();

// !focus(1:3)
const mintCloseAuthorityExtension = extension("MintCloseAuthority", {
  closeAuthority: client.payer.address
});

// !focus(1:1)
const mintSpace = BigInt(getMintSize([mintCloseAuthorityExtension]));
```

## !!steps Calculate rent

Calculate rent using the size needed for the mint plus the
_rs`MintCloseAuthority`_ extension.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const destination = await generateKeyPairSigner();

const mintCloseAuthorityExtension = extension("MintCloseAuthority", {
  closeAuthority: client.payer.address
});

const mintSpace = BigInt(getMintSize([mintCloseAuthorityExtension]));

// !focus(1:3)
const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();
```

## !!steps Create the mint account

Create the mint account with the calculated space and lamports.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const destination = await generateKeyPairSigner();

const mintCloseAuthorityExtension = extension("MintCloseAuthority", {
  closeAuthority: client.payer.address
});

const mintSpace = BigInt(getMintSize([mintCloseAuthorityExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

// !focus(1:9)
await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  })
]);
```

## !!steps Initialize MintCloseAuthority

Initialize the _rs`MintCloseAuthority`_ extension on the mint.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const destination = await generateKeyPairSigner();

const mintCloseAuthorityExtension = extension("MintCloseAuthority", {
  closeAuthority: client.payer.address
});

const mintSpace = BigInt(getMintSize([mintCloseAuthorityExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  }),
  // !focus(1:4)
  getInitializeMintCloseAuthorityInstruction({
    mint: mint.address,
    closeAuthority: client.payer.address
  })
]);
```

## !!steps Initialize the mint

Initialize the mint with _rs`InitializeMint`_ in the same transaction.

<CodePlaceholder title="Example" />

```ts !! title="Example"
const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const destination = await generateKeyPairSigner();

const mintCloseAuthorityExtension = extension("MintCloseAuthority", {
  closeAuthority: client.payer.address
});

const mintSpace = BigInt(getMintSize([mintCloseAuthorityExtension]));

const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  }),
  getInitializeMintCloseAuthorityInstruction({
    mint: mint.address,
    closeAuthority: client.payer.address
  }),
  // !focus(1:6)
  getInitializeMintInstruction({
    mint: mint.address,
    decimals: 0,
    mintAuthority: client.payer.address,
    freezeAuthority: client.payer.address
  })
]);
```

</ScrollyCoding>

<Callout type="info" title="Instruction Order">
  _rs`InitializeMintCloseAuthority`_ must come before _rs`InitializeMint`_.
  _rs`CreateAccount`_, _rs`InitializeMintCloseAuthority`_, and
  _rs`InitializeMint`_ must be included in the same transaction.
</Callout>

### Source Reference

| Item                                          | Description                                                                                     | Source                                                                                                                                |
| --------------------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| _rs`MintCloseAuthority`_                      | Mint extension that stores the authority allowed to close a mint once its supply reaches zero.  | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/extension/mint_close_authority.rs#L14-L20) |
| _rs`InitializeMintCloseAuthority`_            | Instruction that initializes the mint close authority before _rs`InitializeMint`_.              | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/instruction.rs#L1830-L1843)                |
| _rs`CloseAccount`_                            | Base token instruction that closes the mint account after the total supply reaches zero.        | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/instruction.rs#L1582-L1608)                |
| _rs`process_initialize_mint_close_authority`_ | Processor logic that writes the _rs`MintCloseAuthority`_ extension onto an uninitialized mint.  | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/program/src/processor.rs#L1376-L1389)                    |
| _rs`process_close_account`_                   | Shared close-account handler that enforces the zero-supply rule for mints with close authority. | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/program/src/processor.rs#L1197-L1288)                    |

### Typescript

The `Kit` example below uses the generated instructions directly. Legacy
examples using `@solana/web3.js` and `@solana/spl-token` are included for
reference.

#### Kit

<CodeTabs storage="token-ts-kit" flags="r">

```ts !! title="Instructions"
import { lamports, createClient, generateKeyPairSigner } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
  extension,
  findAssociatedTokenPda,
  getBurnCheckedInstruction,
  getCloseAccountInstruction,
  getCreateAssociatedTokenInstructionAsync,
  getInitializeMintCloseAuthorityInstruction,
  getInitializeMintInstruction,
  getMintSize,
  getMintToCheckedInstruction,
  TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const destination = await generateKeyPairSigner();

const mintCloseAuthorityExtension = extension("MintCloseAuthority", {
  closeAuthority: client.payer.address
});
const mintSpace = BigInt(getMintSize([mintCloseAuthorityExtension]));
const mintRent = await client.rpc
  .getMinimumBalanceForRentExemption(mintSpace)
  .send();

await client.sendTransaction([
  getCreateAccountInstruction({
    payer: client.payer,
    newAccount: mint,
    lamports: mintRent,
    space: mintSpace,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS
  }),
  // !mark(1:4)
  getInitializeMintCloseAuthorityInstruction({
    mint: mint.address, // Mint account that stores the MintCloseAuthority extension.
    closeAuthority: client.payer.address // Authority allowed to close the mint.
  }),
  getInitializeMintInstruction({
    mint: mint.address,
    decimals: 0,
    mintAuthority: client.payer.address,
    freezeAuthority: client.payer.address
  })
]);

const [token] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: client.payer.address,
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

await client.sendTransaction([
  await getCreateAssociatedTokenInstructionAsync({
    payer: client.payer,
    mint: mint.address,
    owner: client.payer.address
  }),
  getMintToCheckedInstruction({
    mint: mint.address,
    token,
    mintAuthority: client.payer,
    amount: 1n,
    decimals: 0
  })
]);

await client.sendTransaction([
  getBurnCheckedInstruction({
    mint: mint.address,
    account: token,
    authority: client.payer,
    amount: 1n,
    decimals: 0
  }),
  // !mark(1:5)
  getCloseAccountInstruction({
    account: mint.address, // Mint account to close.
    destination: destination.address, // Account receiving the reclaimed lamports.
    owner: client.payer // Close authority signing the instruction.
  })
]);

const mintInfo = await client.rpc.getAccountInfo(mint.address).send();

console.log("Mint Address:", mint.address);
console.log("Destination Address:", destination.address);
console.log("Mint Closed:", mintInfo.value === null);
```

</CodeTabs>

#### Web3.js

<CodeTabs storage="token-ts-legacy" flags="r">

```ts !! title="Instructions"
import {
  Connection,
  Keypair,
  sendAndConfirmTransaction,
  SystemProgram,
  Transaction,
  LAMPORTS_PER_SOL
} from "@solana/web3.js";
import {
  createInitializeMintInstruction,
  ExtensionType,
  getMintLen,
  createInitializeMintCloseAuthorityInstruction,
  TOKEN_2022_PROGRAM_ID,
  createCloseAccountInstruction
} from "@solana/spl-token";

const connection = new Connection("http://localhost:8899", "confirmed");
const latestBlockhash = await connection.getLatestBlockhash();

const feePayer = Keypair.generate();

const destination = Keypair.generate();

const airdropSignature = await connection.requestAirdrop(
  feePayer.publicKey,
  5 * LAMPORTS_PER_SOL
);
await connection.confirmTransaction({
  blockhash: latestBlockhash.blockhash,
  lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
  signature: airdropSignature
});

const mint = Keypair.generate();

const extensions = [ExtensionType.MintCloseAuthority];

const mintLength = getMintLen(extensions);

const mintRent = await connection.getMinimumBalanceForRentExemption(mintLength);

const createAccountInstruction = SystemProgram.createAccount({
  fromPubkey: feePayer.publicKey,
  newAccountPubkey: mint.publicKey,
  space: mintLength,
  lamports: mintRent,
  programId: TOKEN_2022_PROGRAM_ID
});

// !mark(1:6)
const initializeMintCloseAuthorityInstruction =
  createInitializeMintCloseAuthorityInstruction(
    mint.publicKey, // Mint account that stores the MintCloseAuthority extension.
    feePayer.publicKey, // Authority allowed to close the mint.
    TOKEN_2022_PROGRAM_ID // Token program that owns the mint.
  );

const initializeMintInstruction = createInitializeMintInstruction(
  mint.publicKey, // mint pubkey
  9, // decimals
  feePayer.publicKey, // mint authority
  feePayer.publicKey, // freeze authority
  TOKEN_2022_PROGRAM_ID
);

const transaction = new Transaction({
  feePayer: feePayer.publicKey,
  blockhash: latestBlockhash.blockhash,
  lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
}).add(
  createAccountInstruction,
  initializeMintCloseAuthorityInstruction,
  initializeMintInstruction
);

const transactionSignature = await sendAndConfirmTransaction(
  connection,
  transaction,
  [feePayer, mint]
);

console.log("Mint Address:", mint.publicKey.toBase58());
console.log("Transaction Signature:", transactionSignature);

const latestBlockhash2 = await connection.getLatestBlockhash();

// !mark(1:6)
const closeMintInstruction = createCloseAccountInstruction(
  mint.publicKey, // Mint account to close.
  destination.publicKey, // Account receiving the reclaimed lamports.
  feePayer.publicKey, // Close authority signing the instruction.
  [], // Additional multisig signers.
  TOKEN_2022_PROGRAM_ID // Token program that owns the mint.
);

const closeMintTransaction = new Transaction({
  feePayer: feePayer.publicKey,
  blockhash: latestBlockhash2.blockhash,
  lastValidBlockHeight: latestBlockhash2.lastValidBlockHeight
}).add(closeMintInstruction);

const transactionSignature3 = await sendAndConfirmTransaction(
  connection,
  closeMintTransaction,
  [feePayer]
);

console.log("\nDestination Address:", destination.publicKey.toBase58());
console.log("Transaction Signature:", transactionSignature3);
```

</CodeTabs>

### Rust

<CodeTabs storage="token-rs" flags="r">

```rust !! title="Rust"
use anyhow::Result;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_commitment_config::CommitmentConfig;
use solana_sdk::{
    signature::{Keypair, Signer},
    transaction::Transaction,
};
use solana_system_interface::instruction::create_account;
use spl_token_2022_interface::{
    extension::{
        mint_close_authority::MintCloseAuthority, BaseStateWithExtensions, ExtensionType,
        StateWithExtensions,
    },
    instruction::{close_account, initialize_mint, initialize_mint_close_authority},
    state::Mint,
    ID as TOKEN_2022_PROGRAM_ID,
};

#[tokio::main]
async fn main() -> Result<()> {
    let client = RpcClient::new_with_commitment(
        String::from("http://localhost:8899"),
        CommitmentConfig::confirmed(),
    );
    let fee_payer = Keypair::new();

    let destination = Keypair::new();

    let airdrop_signature = client
        .request_airdrop(&fee_payer.pubkey(), 5_000_000_000)
        .await?;

    loop {
        let confirmed = client.confirm_transaction(&airdrop_signature).await?;
        if confirmed {
            break;
        }
    }

    let mint = Keypair::new();

    let mint_space =
        ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::MintCloseAuthority])?;

    let mint_rent = client
        .get_minimum_balance_for_rent_exemption(mint_space)
        .await?;

    let create_account_instruction = create_account(
        &fee_payer.pubkey(),    // payer
        &mint.pubkey(),         // new account (mint)
        mint_rent,              // lamports
        mint_space as u64,      // space
        &TOKEN_2022_PROGRAM_ID, // program id
    );

    // !mark(1:5)
    let initialize_close_mint_instruction = initialize_mint_close_authority(
        &TOKEN_2022_PROGRAM_ID,    // token program
        &mint.pubkey(),            // mint
        Some(&fee_payer.pubkey()), // close authority
    )?;

    let initialize_mint_instruction = initialize_mint(
        &TOKEN_2022_PROGRAM_ID,    // token program
        &mint.pubkey(),            // mint
        &fee_payer.pubkey(),       // mint authority
        Some(&fee_payer.pubkey()), // freeze authority
        9,                         // decimals
    )?;

    let transaction = Transaction::new_signed_with_payer(
        &[
            create_account_instruction,
            initialize_close_mint_instruction,
            initialize_mint_instruction,
        ],
        Some(&fee_payer.pubkey()),
        &[&fee_payer, &mint],
        client.get_latest_blockhash().await?,
    );

    client.send_and_confirm_transaction(&transaction).await?;

    println!("Mint Address: {}", mint.pubkey());

    let mint_account = client.get_account(&mint.pubkey()).await?;
    let mint_state = StateWithExtensions::<Mint>::unpack(&mint_account.data)?;

    let mint_extension_types = mint_state.get_extension_types()?;
    println!("\nMint extensions enabled: {:?}", mint_extension_types);

    let mint_close_authority = mint_state.get_extension::<MintCloseAuthority>()?;
    println!("\n{:#?}", mint_close_authority);

    // !mark(1:6)
    let close_mint_instruction = close_account(
        &TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
        &mint.pubkey(), // Mint account to close.
        &destination.pubkey(), // Account receiving the reclaimed lamports.
        &fee_payer.pubkey(), // Close authority signing the instruction.
        &[&fee_payer.pubkey()], // Additional multisig signers.
    )?;

    let transaction = Transaction::new_signed_with_payer(
        &[close_mint_instruction],
        Some(&fee_payer.pubkey()),
        &[&fee_payer],
        client.get_latest_blockhash().await?,
    );

    client.send_and_confirm_transaction(&transaction).await?;

    match client.get_account(&mint.pubkey()).await {
        Ok(_) => println!("\nMint account still exists (unexpected)"),
        Err(e) => println!("\nMint account successfully closed: {:#?}", e),
    }

    Ok(())
}
```

</CodeTabs>
