Trạng thái mặc định

Trạng Thái Tài Khoản Mặc Định Là Gì?

Tiện ích mở rộng mint DefaultAccountState của Token Extensions Program thiết lập AccountState ban đầu cho mọi token account mới được tạo cho mint đó.

Điều này thường được sử dụng để làm cho các token account mới bắt đầu ở trạng thái đóng băng. Các token account bắt đầu bị đóng băng không thể được sử dụng cho đến khi quyền hạn đóng băng của mint thực hiện rã đóng băng cho chúng.

Cách Tạo Mint Với Trạng Thái Tài Khoản Mặc Định

Để tạo một mint với trạng thái tài khoản mặc định:

  1. Tính toán kích thước mint account và rent cần thiết cho mint và tiện ích mở rộng DefaultAccountState.
  2. Tạo mint account với CreateAccount, khởi tạo DefaultAccountState, và khởi tạo mint với InitializeMint.
  3. Tạo các token account cho mint và quan sát rằng mỗi token account mới bắt đầu ở trạng thái mặc định hiện tại.
  4. Sử dụng UpdateDefaultAccountState để thay đổi trạng thái mà các token account trong tương lai nên bắt đầu.

Tính toán kích thước tài khoản

Tính toán kích thước mint account cho mint cơ bản cộng với tiện ích mở rộng DefaultAccountState. Đây là kích thước được sử dụng trong CreateAccount.

Tính toán rent

Tính toán rent sử dụng kích thước cần thiết cho mint cộng với tiện ích mở rộng DefaultAccountState.

Tạo mint account

Tạo mint account với dung lượng và lamport đã tính toán.

Khởi tạo DefaultAccountState

Khởi tạo extension DefaultAccountState trên mint.

Khởi tạo mint

Khởi tạo mint với InitializeMint trong cùng một giao dịch.

Tạo token account

Tạo một token account cho mint. Vì trạng thái mặc định hiện tại là Frozen, nên token account mới sẽ bắt đầu ở trạng thái đóng băng.

Cập nhật trạng thái mặc định của account

Sử dụng UpdateDefaultAccountState để thay đổi trạng thái mặc định sao cho các token account trong tương lai không còn bắt đầu ở trạng thái đóng băng nữa.

Tính toán kích thước tài khoản

Tính toán kích thước mint account cho mint cơ bản cộng với tiện ích mở rộng DefaultAccountState. Đây là kích thước được sử dụng trong CreateAccount.

Tính toán rent

Tính toán rent sử dụng kích thước cần thiết cho mint cộng với tiện ích mở rộng DefaultAccountState.

Tạo mint account

Tạo mint account với dung lượng và lamport đã tính toán.

Khởi tạo DefaultAccountState

Khởi tạo extension DefaultAccountState trên mint.

Khởi tạo mint

Khởi tạo mint với InitializeMint trong cùng một giao dịch.

Tạo token account

Tạo một token account cho mint. Vì trạng thái mặc định hiện tại là Frozen, nên token account mới sẽ bắt đầu ở trạng thái đóng băng.

Cập nhật trạng thái mặc định của account

Sử dụng UpdateDefaultAccountState để thay đổi trạng thái mặc định sao cho các token account trong tương lai không còn bắt đầu ở trạng thái đóng băng nữa.

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 recipient = await generateKeyPairSigner();
const defaultAccountStateExtension = extension("DefaultAccountState", {
state: AccountState.Frozen
});
const mintSpace = BigInt(getMintSize([defaultAccountStateExtension]));

Thứ tự lệnh

DefaultAccountStateInstruction::Initialize phải được thực hiện trước InitializeMint. CreateAccount, DefaultAccountStateInstruction::Initialize, và InitializeMint phải được bao gồm trong cùng một giao dịch.

Tài liệu tham khảo mã nguồn

MụcMô tảNguồn
DefaultAccountStateExtension của mint lưu trữ trạng thái mà các token account mới sẽ kế thừa.Nguồn
DefaultAccountStateInstruction::InitializeLệnh khởi tạo trạng thái mặc định của token account cho mint trước InitializeMint.Nguồn
DefaultAccountStateInstruction::UpdateLệnh cho phép freeze authority thay đổi trạng thái mặc định cho các token account trong tương lai.Nguồn
process_initialize_default_account_stateLogic xử lý ghi trạng thái mặc định ban đầu lên mint chưa được khởi tạo.Nguồn
process_update_default_account_stateLogic xử lý xác minh freeze authority trước khi thay đổi trạng thái mặc định được lưu trữ của mint.Nguồn

Typescript

Ví dụ Kit bên dưới sử dụng trực tiếp các lệnh được tạo. Các ví dụ cũ sử dụng @solana/web3.js@solana/spl-token được đưa vào để tham khảo.

Kit

Instructions
import {
lamports,
createClient,
generateKeyPairSigner,
unwrapOption
} 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 {
AccountState,
extension,
fetchMint,
fetchToken,
findAssociatedTokenPda,
getCreateAssociatedTokenInstructionAsync,
getInitializeDefaultAccountStateInstruction,
getInitializeMintInstruction,
getMintSize,
getUpdateDefaultAccountStateInstruction,
isExtension,
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 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?

Mục lục

Chỉnh sửa trang

Quản lý bởi

© 2026 Solana Foundation.
Đã đăng ký bản quyền.
Kết nối