Fechar Mint

O Que É Autoridade de Fechamento de Mint?

A extensão de mint MintCloseAuthority do Token Extensions Program permite que uma autoridade designada feche uma mint account e recupere seu rent assim que o fornecimento total do mint chegar a zero.

Sem esta extensão, uma mint account não pode ser fechada.

  • O fornecimento total deve ser zero, portanto todos os tokens em todas as token accounts devem ser queimados antes que um mint possa ser fechado
  • Apenas a autoridade de fechamento configurada pode fechar o mint

Como Criar e Fechar um Mint

Para criar e fechar um mint:

  1. Calcule o tamanho da mint account e o rent necessário para o mint e a extensão MintCloseAuthority.
  2. Crie a mint account com CreateAccount, inicialize MintCloseAuthority e inicialize o mint com InitializeMint.
  3. Se o fornecimento total for zero, a mint account pode ser fechada com CloseAccount, assinado pela autoridade de fechamento.

Calcular tamanho da conta

Calcule o tamanho da mint account para o mint base mais a extensão MintCloseAuthority. Este é o tamanho usado em CreateAccount.

Calcular rent

Calcule o rent usando o tamanho necessário para o mint mais a extensão MintCloseAuthority.

Criar a mint account

Crie a mint account com o espaço e lamports calculados.

Inicializar MintCloseAuthority

Inicialize a extensão MintCloseAuthority na mint.

Inicializar a mint

Inicialize a mint com InitializeMint na mesma transação.

Calcular tamanho da conta

Calcule o tamanho da mint account para o mint base mais a extensão MintCloseAuthority. Este é o tamanho usado em CreateAccount.

Calcular rent

Calcule o rent usando o tamanho necessário para o mint mais a extensão MintCloseAuthority.

Criar a mint account

Crie a mint account com o espaço e lamports calculados.

Inicializar MintCloseAuthority

Inicialize a extensão MintCloseAuthority na mint.

Inicializar a mint

Inicialize a mint com InitializeMint na mesma transação.

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]));

Ordem das Instruções

InitializeMintCloseAuthority deve vir antes de InitializeMint. CreateAccount, InitializeMintCloseAuthority e InitializeMint devem ser incluídos na mesma transação.

Referência da Fonte

ItemDescriçãoFonte
MintCloseAuthorityExtensão de mint que armazena a autoridade permitida para fechar uma mint quando seu fornecimento chega a zero.Fonte
InitializeMintCloseAuthorityInstrução que inicializa a autoridade de fechamento de mint antes de InitializeMint.Fonte
CloseAccountInstrução base de token que fecha a mint account após o fornecimento total atingir zero.Fonte
process_initialize_mint_close_authorityLógica do processador que grava a extensão MintCloseAuthority em uma mint não inicializada.Fonte
process_close_accountManipulador compartilhado de fechamento de conta que impõe a regra de fornecimento zero para mints com autoridade de fechamento.Fonte

Typescript

O exemplo Kit abaixo utiliza as instruções geradas diretamente. Exemplos legados usando @solana/web3.js e @solana/spl-token estão incluídos para referência.

Kit

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
}),
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
}),
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);
Console
Click to execute the code.

Web3.js

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
});
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();
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);
Console
Click to execute the code.

Rust

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
);
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);
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(())
}
Console
Click to execute the code.

Is this page helpful?

Índice

Editar Página

Gerenciado por

© 2026 Fundação Solana.
Todos os direitos reservados.
Conecte-se
  • Blog