État par défaut

Qu'est-ce que l'état de compte par défaut ?

L'extension de mint DefaultAccountState du Token Extensions Program définit l'AccountState initial pour chaque nouveau compte de jetons créé pour ce mint.

Cette fonctionnalité est le plus souvent utilisée pour que les nouveaux comptes de jetons démarrent gelés. Les comptes de jetons qui démarrent gelés ne peuvent pas être utilisés tant que l'autorité de gel du mint ne les a pas dégelés.

Comment créer un mint avec un état de compte par défaut

Pour créer un mint avec un état de compte par défaut :

  1. Calculez la taille du compte de mint et le loyer nécessaire pour le mint et l'extension DefaultAccountState.
  2. Créez le compte de mint avec CreateAccount, initialisez DefaultAccountState, puis initialisez le mint avec InitializeMint.
  3. Créez des comptes de jetons pour le mint et observez que chaque nouveau compte de jetons démarre dans l'état par défaut actuel.
  4. Utilisez UpdateDefaultAccountState pour modifier l'état dans lequel les futurs comptes de jetons doivent démarrer.

Calculer la taille du compte

Calculez la taille du compte de mint pour le mint de base plus l'extension DefaultAccountState. C'est la taille utilisée dans CreateAccount.

Calculer le loyer

Calculez le loyer en utilisant la taille nécessaire pour le mint plus l'extension DefaultAccountState.

Créer le compte de mint

Créez le compte de mint avec l'espace et les lamports calculés.

Initialiser DefaultAccountState

Initialisez l'extension DefaultAccountState sur le mint.

Initialiser le mint

Initialisez le mint avec InitializeMint dans la même transaction.

Créer un token account

Créez un token account pour le mint. Étant donné que l'état par défaut actuel est Frozen, le nouveau token account démarre gelé.

Mettre à jour l'état par défaut du compte

Utilisez UpdateDefaultAccountState pour modifier l'état par défaut afin que les futurs token accounts ne démarrent plus gelés.

Calculer la taille du compte

Calculez la taille du compte de mint pour le mint de base plus l'extension DefaultAccountState. C'est la taille utilisée dans CreateAccount.

Calculer le loyer

Calculez le loyer en utilisant la taille nécessaire pour le mint plus l'extension DefaultAccountState.

Créer le compte de mint

Créez le compte de mint avec l'espace et les lamports calculés.

Initialiser DefaultAccountState

Initialisez l'extension DefaultAccountState sur le mint.

Initialiser le mint

Initialisez le mint avec InitializeMint dans la même transaction.

Créer un token account

Créez un token account pour le mint. Étant donné que l'état par défaut actuel est Frozen, le nouveau token account démarre gelé.

Mettre à jour l'état par défaut du compte

Utilisez UpdateDefaultAccountState pour modifier l'état par défaut afin que les futurs token accounts ne démarrent plus gelés.

Example
const client = await createLocalClient();
const mint = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
const defaultAccountStateExtension = extension("DefaultAccountState", {
state: AccountState.Frozen
});
const mintSpace = BigInt(getMintSize([defaultAccountStateExtension]));

Ordre des instructions

DefaultAccountStateInstruction::Initialize doit précéder InitializeMint. CreateAccount, DefaultAccountStateInstruction::Initialize et InitializeMint doivent être inclus dans la même transaction.

Référence source

ÉlémentDescriptionSource
DefaultAccountStateExtension de mint qui stocke l'état que les nouveaux token accounts doivent hériter.Source
DefaultAccountStateInstruction::InitializeInstruction qui initialise l'état par défaut du token account du mint avant InitializeMint.Source
DefaultAccountStateInstruction::UpdateInstruction qui permet à l'autorité de gel de modifier l'état par défaut pour les futurs token accounts.Source
process_initialize_default_account_stateLogique de traitement qui écrit l'état par défaut initial sur un mint non initialisé.Source
process_update_default_account_stateLogique de traitement qui vérifie l'autorité de gel avant de modifier l'état par défaut stocké du mint.Source

Typescript

L'exemple Kit ci-dessous utilise directement les instructions générées. Des exemples hérités utilisant @solana/web3.js et @solana/spl-token sont inclus à titre de référence.

Kit

Instructions
import { generateKeyPairSigner, unwrapOption } from "@solana/kit";
import { createLocalClient } from "@solana/kit-client-rpc";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
AccountState,
extension,
fetchMint,
fetchToken,
findAssociatedTokenPda,
getCreateAssociatedTokenInstructionAsync,
getInitializeDefaultAccountStateInstruction,
getInitializeMintInstruction,
getMintSize,
getUpdateDefaultAccountStateInstruction,
isExtension,
TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";
const client = await createLocalClient();
const mint = await generateKeyPairSigner();
const getAccountStateLabel = (state: AccountState) => {
switch (state) {
case AccountState.Frozen:
return "Frozen";
case AccountState.Initialized:
return "Initialized";
default:
return "Uninitialized";
}
};
const defaultAccountStateExtension = extension("DefaultAccountState", {
state: AccountState.Frozen
});
const mintSpace = BigInt(getMintSize([defaultAccountStateExtension]));
const mintRent = await client.rpc
.getMinimumBalanceForRentExemption(mintSpace)
.send();
await client.sendTransaction([
getCreateAccountInstruction({
payer: client.payer, // Account funding the new mint account.
newAccount: mint, // New mint account to create.
lamports: mintRent, // Lamports funding the mint account rent.
space: mintSpace, // Account size in bytes for the mint plus DefaultAccountState.
programAddress: TOKEN_2022_PROGRAM_ADDRESS // Program that owns the mint account.
}),
getInitializeDefaultAccountStateInstruction({
mint: mint.address, // Mint account that stores the DefaultAccountState extension.
state: AccountState.Frozen // Default state assigned to new token accounts.
}),
getInitializeMintInstruction({
mint: mint.address, // Mint account to initialize.
decimals: 0, // Number of decimals for the token.
mintAuthority: client.payer.address, // Authority allowed to mint new tokens.
freezeAuthority: client.payer.address // Authority allowed to freeze token accounts.
})
]);
const [tokenAccount] = await findAssociatedTokenPda({
mint: mint.address,
owner: client.payer.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
await client.sendTransaction([
await getCreateAssociatedTokenInstructionAsync({
payer: client.payer, // Account funding the associated token account creation.
mint: mint.address, // Mint for the associated token account.
owner: client.payer.address // Owner of the token account.
})
]);
const tokenAccountBeforeUpdate = await fetchToken(client.rpc, tokenAccount);
const mintAccountBeforeUpdate = await fetchMint(client.rpc, mint.address);
const defaultAccountStateBeforeUpdate = (
unwrapOption(mintAccountBeforeUpdate.data.extensions) ?? []
).find((item) => isExtension("DefaultAccountState", item));
await client.sendTransaction([
getUpdateDefaultAccountStateInstruction({
mint: mint.address, // Mint account that stores the DefaultAccountState extension.
freezeAuthority: client.payer, // Freeze authority authorized to update the default state.
state: AccountState.Initialized // New default state assigned to later token accounts.
})
]);
const tokenAccountAfterUpdate = await fetchToken(client.rpc, tokenAccount);
const mintAccountAfterUpdate = await fetchMint(client.rpc, mint.address);
const defaultAccountStateAfterUpdate = (
unwrapOption(mintAccountAfterUpdate.data.extensions) ?? []
).find((item) => isExtension("DefaultAccountState", item));
console.log("Mint Address:", mint.address);
console.log(
"Default Account State Before Update:",
defaultAccountStateBeforeUpdate
);
console.log(
"Token Account State Before Update:",
getAccountStateLabel(tokenAccountBeforeUpdate.data.state)
);
console.log(
"Default Account State After Update:",
defaultAccountStateAfterUpdate
);
console.log(
"Token Account State After Update:",
getAccountStateLabel(tokenAccountAfterUpdate.data.state)
);
Console
Click to execute the code.

Web3.js

Instructions
import {
Connection,
Keypair,
sendAndConfirmTransaction,
SystemProgram,
Transaction,
LAMPORTS_PER_SOL
} from "@solana/web3.js";
import {
AccountState,
ASSOCIATED_TOKEN_PROGRAM_ID,
createAssociatedTokenAccountInstruction,
createInitializeDefaultAccountStateInstruction,
createInitializeMintInstruction,
createUpdateDefaultAccountStateInstruction,
ExtensionType,
getAccount,
getAssociatedTokenAddressSync,
getDefaultAccountState,
getMint,
getMintLen,
TOKEN_2022_PROGRAM_ID
} from "@solana/spl-token";
const connection = new Connection("http://localhost:8899", "confirmed");
const latestBlockhash = await connection.getLatestBlockhash();
const feePayer = Keypair.generate();
const getTokenAccountStateLabel = (account: {
isInitialized: boolean;
isFrozen: boolean;
}) => {
if (account.isFrozen) return "Frozen";
if (account.isInitialized) return "Initialized";
return "Uninitialized";
};
const airdropSignature = await connection.requestAirdrop(
feePayer.publicKey,
5 * LAMPORTS_PER_SOL
);
await connection.confirmTransaction({
blockhash: latestBlockhash.blockhash,
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
signature: airdropSignature
});
const extensions = [ExtensionType.DefaultAccountState];
const mint = Keypair.generate();
const mintLength = getMintLen(extensions);
const mintRent = await connection.getMinimumBalanceForRentExemption(mintLength);
const createMintAccountInstruction = SystemProgram.createAccount({
fromPubkey: feePayer.publicKey, // Account funding the new mint account.
newAccountPubkey: mint.publicKey, // New mint account to create.
space: mintLength, // Account size in bytes for the mint plus DefaultAccountState.
lamports: mintRent, // Lamports funding the mint account rent.
programId: TOKEN_2022_PROGRAM_ID // Program that owns the mint account.
});
const initializeDefaultStateInstruction =
createInitializeDefaultAccountStateInstruction(
mint.publicKey, // Mint account that stores the DefaultAccountState extension.
AccountState.Frozen, // Default state assigned to new token accounts.
TOKEN_2022_PROGRAM_ID // Token program that owns the mint.
);
const initializeMintInstruction = createInitializeMintInstruction(
mint.publicKey, // Mint account to initialize.
0, // Number of decimals for the token.
feePayer.publicKey, // Authority allowed to mint new tokens.
feePayer.publicKey, // Authority allowed to freeze token accounts.
TOKEN_2022_PROGRAM_ID // Program that owns the mint account.
);
await sendAndConfirmTransaction(
connection,
new Transaction({
feePayer: feePayer.publicKey,
blockhash: latestBlockhash.blockhash,
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
}).add(
createMintAccountInstruction,
initializeDefaultStateInstruction,
initializeMintInstruction
),
[feePayer, mint]
);
const tokenAccount = getAssociatedTokenAddressSync(
mint.publicKey,
feePayer.publicKey,
false,
TOKEN_2022_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
);
await sendAndConfirmTransaction(
connection,
new Transaction().add(
createAssociatedTokenAccountInstruction(
feePayer.publicKey, // Account funding the associated token account creation.
tokenAccount, // Associated token account address to create.
feePayer.publicKey, // Owner of the token account.
mint.publicKey, // Mint for the associated token account.
TOKEN_2022_PROGRAM_ID, // Token program that owns the token account.
ASSOCIATED_TOKEN_PROGRAM_ID // Associated Token Program that creates the account.
)
),
[feePayer],
{
commitment: "confirmed"
}
);
const tokenAccountBeforeUpdate = await getAccount(
connection,
tokenAccount,
"confirmed",
TOKEN_2022_PROGRAM_ID
);
const mintAccountBeforeUpdate = await getMint(
connection,
mint.publicKey,
"confirmed",
TOKEN_2022_PROGRAM_ID
);
const defaultAccountStateBeforeUpdate = getDefaultAccountState(
mintAccountBeforeUpdate
);
const updateDefaultStateInstruction =
createUpdateDefaultAccountStateInstruction(
mint.publicKey, // Mint account that stores the DefaultAccountState extension.
AccountState.Initialized, // New default state assigned to later token accounts.
feePayer.publicKey, // Freeze authority authorized to update the default state.
[], // Additional multisig signers.
TOKEN_2022_PROGRAM_ID // Token program that owns the mint.
);
await sendAndConfirmTransaction(
connection,
new Transaction().add(updateDefaultStateInstruction),
[feePayer],
{
commitment: "confirmed"
}
);
const tokenAccountAfterUpdate = await getAccount(
connection,
tokenAccount,
"confirmed",
TOKEN_2022_PROGRAM_ID
);
const mintAccountAfterUpdate = await getMint(
connection,
mint.publicKey,
"confirmed",
TOKEN_2022_PROGRAM_ID
);
const defaultAccountStateAfterUpdate = getDefaultAccountState(
mintAccountAfterUpdate
);
console.log("Mint Address:", mint.publicKey.toBase58());
console.log(
"Default Account State Before Update:",
defaultAccountStateBeforeUpdate
);
console.log(
"Token Account State Before Update:",
getTokenAccountStateLabel(tokenAccountBeforeUpdate)
);
console.log(
"Default Account State After Update:",
defaultAccountStateAfterUpdate
);
console.log(
"Token Account State After Update:",
getTokenAccountStateLabel(tokenAccountAfterUpdate)
);
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_associated_token_account_interface::{
address::get_associated_token_address_with_program_id,
instruction::create_associated_token_account,
};
use spl_token_2022_interface::{
extension::{
default_account_state::{
instruction::{initialize_default_account_state, update_default_account_state},
DefaultAccountState,
},
BaseStateWithExtensions, ExtensionType, StateWithExtensions,
},
instruction::initialize_mint,
state::{Account, AccountState, Mint},
ID as TOKEN_2022_PROGRAM_ID,
};
fn get_account_state_label(state: AccountState) -> &'static str {
match state {
AccountState::Frozen => "Frozen",
AccountState::Initialized => "Initialized",
AccountState::Uninitialized => "Uninitialized",
}
}
#[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 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::DefaultAccountState])?;
let mint_rent = client
.get_minimum_balance_for_rent_exemption(mint_space)
.await?;
let create_mint_account_instruction = create_account(
&fee_payer.pubkey(), // Account funding the new mint account.
&mint.pubkey(), // New mint account to create.
mint_rent, // Lamports funding the mint account rent.
mint_space as u64, // Account size in bytes for the mint plus DefaultAccountState.
&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.
);
let initialize_default_account_state_instruction = initialize_default_account_state(
&TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
&mint.pubkey(), // Mint account that stores the DefaultAccountState extension.
&AccountState::Frozen, // Default state assigned to new token accounts.
)?;
let initialize_mint_instruction = initialize_mint(
&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.
&mint.pubkey(), // Mint account to initialize.
&fee_payer.pubkey(), // Authority allowed to mint new tokens.
Some(&fee_payer.pubkey()), // Authority allowed to freeze token accounts.
0, // Number of decimals for the token.
)?;
let create_mint_transaction = Transaction::new_signed_with_payer(
&[
create_mint_account_instruction,
initialize_default_account_state_instruction,
initialize_mint_instruction,
],
Some(&fee_payer.pubkey()),
&[&fee_payer, &mint],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&create_mint_transaction)
.await?;
let token_account = get_associated_token_address_with_program_id(
&fee_payer.pubkey(),
&mint.pubkey(),
&TOKEN_2022_PROGRAM_ID,
);
let create_token_account_transaction = Transaction::new_signed_with_payer(
&[create_associated_token_account(
&fee_payer.pubkey(), // Account funding the associated token account creation.
&fee_payer.pubkey(), // Owner of the token account.
&mint.pubkey(), // Mint for the associated token account.
&TOKEN_2022_PROGRAM_ID, // Token program that owns the token account.
)],
Some(&fee_payer.pubkey()),
&[&fee_payer],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&create_token_account_transaction)
.await?;
let token_account_data_before_update = client.get_account(&token_account).await?;
let token_account_state_before_update =
StateWithExtensions::<Account>::unpack(&token_account_data_before_update.data)?;
let mint_account_before_update = client.get_account(&mint.pubkey()).await?;
let mint_state_before_update =
StateWithExtensions::<Mint>::unpack(&mint_account_before_update.data)?;
let default_account_state_before_update = mint_state_before_update
.get_extension::<DefaultAccountState>()?;
let update_default_account_state_instruction = update_default_account_state(
&TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
&mint.pubkey(), // Mint account that stores the DefaultAccountState extension.
&fee_payer.pubkey(), // Freeze authority authorized to update the default state.
&[&fee_payer.pubkey()], // Additional multisig signers.
&AccountState::Initialized, // New default state assigned to later token accounts.
)?;
let update_default_account_state_transaction = Transaction::new_signed_with_payer(
&[update_default_account_state_instruction],
Some(&fee_payer.pubkey()),
&[&fee_payer],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&update_default_account_state_transaction)
.await?;
let token_account_data_after_update = client.get_account(&token_account).await?;
let token_account_state_after_update =
StateWithExtensions::<Account>::unpack(&token_account_data_after_update.data)?;
let mint_account_after_update = client.get_account(&mint.pubkey()).await?;
let mint_state_after_update =
StateWithExtensions::<Mint>::unpack(&mint_account_after_update.data)?;
let default_account_state_after_update =
mint_state_after_update.get_extension::<DefaultAccountState>()?;
println!("Mint Address: {}", mint.pubkey());
println!(
"Default Account State Before Update: {:?}",
default_account_state_before_update
);
println!(
"Token Account State Before Update: {}",
get_account_state_label(token_account_state_before_update.base.state)
);
println!(
"Default Account State After Update: {:?}",
default_account_state_after_update
);
println!(
"Token Account State After Update: {}",
get_account_state_label(token_account_state_after_update.base.state)
);
Ok(())
}
Console
Click to execute the code.

Is this page helpful?

Table des matières

Modifier la page

Géré par

© 2026 Fondation Solana.
Tous droits réservés.
Restez connecté