一時停止可能なミント

一時停止可能なミントとは?

Token Extensions Programの*rsPausableConfig*ミント拡張機能により、一時停止権限者がミント全体のトークンアクティビティを一時停止および再開できます。

ミントが一時停止されると、Token Extensions Programは以下を拒否します:

  • 転送
  • ミント
  • バーン

ミントが再開されると、これらのinstructionsは再び正常に機能します。

ミントの作成、一時停止、再開の方法

ミントを作成、一時停止、再開するには:

  1. ミントアカウントのサイズと、ミントおよび*rsPausableConfig*拡張機能に必要なrentを計算します。
  2. *rsCreateAccount*でミントアカウントを作成し、*rsPausableConfig*を初期化し、*rsInitializeMint*でミントを初期化します。
  3. トークンをミントし、ミントのためのトークンアカウントを作成します。
  4. *rsPause*を使用してミントのトークンアクティビティをブロックします。
  5. *rsResume*を使用してトークンアクティビティを再び許可します。

アカウントサイズの計算

基本ミントに*rsPausableConfig拡張機能を加えたミントアカウントのサイズを計算します。これはrsCreateAccount*で使用されるサイズです。

rentの計算

ミントに*rsPausableConfig*拡張機能を加えたサイズを使用してrentを計算します。

ミントアカウントの作成

計算されたスペースとlamportを使用してmint accountを作成します。

PausableConfigの初期化

ミント上で*rsPausableConfig*拡張機能を初期化します。

ミントの初期化

同じトランザクション内で*rsInitializeMint*を使用してミントを初期化します。

ミントの一時停止

*rsPause*を使用してミントを一時停止します。

ミントの再開

*rsResume*を使用してミントを再開します。

アカウントサイズの計算

基本ミントに*rsPausableConfig拡張機能を加えたミントアカウントのサイズを計算します。これはrsCreateAccount*で使用されるサイズです。

rentの計算

ミントに*rsPausableConfig*拡張機能を加えたサイズを使用してrentを計算します。

ミントアカウントの作成

計算されたスペースとlamportを使用してmint accountを作成します。

PausableConfigの初期化

ミント上で*rsPausableConfig*拡張機能を初期化します。

ミントの初期化

同じトランザクション内で*rsInitializeMint*を使用してミントを初期化します。

ミントの一時停止

*rsPause*を使用してミントを一時停止します。

ミントの再開

*rsResume*を使用してミントを再開します。

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 pausableExtension = extension("PausableConfig", {
authority: client.payer.address,
paused: false
});
const mintSpace = BigInt(getMintSize([pausableExtension]));

命令の順序

_rsPausableInstruction::Initialize_は_rsInitializeMint_の前に実行する必要があります。 CreateAccountPausableInstruction::Initialize、および_rsInitializeMint_は同じトランザクションに含める必要があります。

ソース参照

項目説明ソース
PausableConfig一時停止権限とミントが現在一時停止されているかどうかを保存するミント拡張機能。ソース
PausableInstruction::Initialize*rsInitializeMint*の前に一時停止可能な設定を初期化するinstructions。ソース
PausableInstruction::Pauseミントを一時停止としてマークするinstructions。ソース
PausableInstruction::Resumeミントの一時停止を解除するinstructions。ソース
process_initialize未初期化のミント上で*rsPausableConfig*を初期化し、一時停止権限を保存するプロセッサロジック。ソース
process_toggle_pauseミントの一時停止フラグを切り替える前に一時停止権限を検証するプロセッサロジック。ソース

Typescript

以下のKitの例では、生成されたinstructionsを直接使用しています。@solana/web3.jsおよび@solana/spl-tokenを使用した従来の例は参考のために含まれています。

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 {
extension,
fetchMint,
findAssociatedTokenPda,
getCreateAssociatedTokenInstructionAsync,
getInitializeMintInstruction,
getInitializePausableConfigInstruction,
getMintSize,
getMintToCheckedInstruction,
getPauseInstruction,
getResumeInstruction,
getTransferCheckedInstruction,
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 recipient = await generateKeyPairSigner();
const pausableExtension = extension("PausableConfig", {
authority: client.payer.address,
paused: false
});
const mintSpace = BigInt(getMintSize([pausableExtension]));
const mintRent = await client.rpc
.getMinimumBalanceForRentExemption(mintSpace)
.send();
await client.sendTransaction([
getCreateAccountInstruction({
payer: client.payer, // Account funding account creation.
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 PausableConfig.
programAddress: TOKEN_2022_PROGRAM_ADDRESS // Program that owns the mint account.
}),
getInitializePausableConfigInstruction({
mint: mint.address, // Mint account that stores the PausableConfig extension.
authority: client.payer.address // Authority allowed to pause and resume the mint.
}),
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 [sourceToken] = await findAssociatedTokenPda({
mint: mint.address,
owner: client.payer.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [destinationToken] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient.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 associated token account.
}),
await getCreateAssociatedTokenInstructionAsync({
payer: client.payer, // Account funding the associated token account creation.
mint: mint.address, // Mint for the associated token account.
owner: recipient.address // Owner of the associated token account.
}),
getMintToCheckedInstruction({
mint: mint.address, // Mint account that issues the tokens.
token: sourceToken, // Token account receiving the newly minted tokens.
mintAuthority: client.payer, // Signer authorized to mint new tokens.
amount: 1n, // Token amount in base units.
decimals: 0 // Decimals defined on the mint.
})
]);
await client.sendTransaction([
getPauseInstruction({
mint: mint.address, // Mint account to pause.
authority: client.payer // Signer authorized to pause the mint.
})
]);
const mintAccountAfterPause = await fetchMint(client.rpc, mint.address);
const configAfterPause = (
unwrapOption(mintAccountAfterPause.data.extensions) ?? []
).find((item) => isExtension("PausableConfig", item));
let pausedTransferFailure: string | undefined;
try {
await client.sendTransaction([
getTransferCheckedInstruction({
source: sourceToken, // Token account sending the transfer.
mint: mint.address, // Mint with the pausable configuration.
destination: destinationToken, // Token account receiving the transfer.
authority: client.payer, // Signer approving the transfer.
amount: 1n, // Token amount in base units.
decimals: 0 // Decimals defined on the mint.
})
]);
} catch (error) {
pausedTransferFailure =
error instanceof Error ? error.message : String(error);
}
if (!pausedTransferFailure) {
throw new Error("Expected the paused transfer to fail");
}
await client.sendTransaction([
getResumeInstruction({
mint: mint.address, // Mint account to resume.
authority: client.payer // Signer authorized to resume the mint.
})
]);
await client.sendTransaction([
getTransferCheckedInstruction({
source: sourceToken, // Token account sending the transfer.
mint: mint.address, // Mint with the pausable configuration.
destination: destinationToken, // Token account receiving the transfer.
authority: client.payer, // Signer approving the transfer.
amount: 1n, // Token amount in base units.
decimals: 0 // Decimals defined on the mint.
})
]);
const mintAccountAfterResume = await fetchMint(client.rpc, mint.address);
const configAfterResume = (
unwrapOption(mintAccountAfterResume.data.extensions) ?? []
).find((item) => isExtension("PausableConfig", item));
console.log("\nMint Address:", mint.address);
console.log("\nConfig After Pause:", configAfterPause);
console.log("\nError From Failed Transaction:", pausedTransferFailure);
console.log("\nConfig After Resume:", configAfterResume);
Console
Click to execute the code.

Web3.js

Instructions
import {
Connection,
Keypair,
LAMPORTS_PER_SOL,
sendAndConfirmTransaction,
SystemProgram,
Transaction
} from "@solana/web3.js";
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
createAssociatedTokenAccountInstruction,
createInitializeMintInstruction,
createInitializePausableConfigInstruction,
createMintToCheckedInstruction,
createPauseInstruction,
createResumeInstruction,
createTransferCheckedInstruction,
ExtensionType,
getAssociatedTokenAddressSync,
getMint,
getMintLen,
getPausableConfig,
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 mint = Keypair.generate();
const recipient = 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 mintSpace = getMintLen([ExtensionType.PausableConfig]);
const mintRent = await connection.getMinimumBalanceForRentExemption(mintSpace);
await sendAndConfirmTransaction(
connection,
new Transaction().add(
SystemProgram.createAccount({
fromPubkey: feePayer.publicKey, // Account funding account creation.
newAccountPubkey: mint.publicKey, // New mint account to create.
space: mintSpace, // Account size in bytes for the mint plus PausableConfig.
lamports: mintRent, // Lamports funding the mint account rent.
programId: TOKEN_2022_PROGRAM_ID // Program that owns the mint account.
}),
createInitializePausableConfigInstruction(
mint.publicKey, // Mint account that stores the PausableConfig extension.
feePayer.publicKey, // Authority allowed to pause and resume the mint.
TOKEN_2022_PROGRAM_ID // Token program that owns the mint.
),
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.
)
),
[feePayer, mint],
{ commitment: "confirmed" }
);
const sourceToken = getAssociatedTokenAddressSync(
mint.publicKey,
feePayer.publicKey,
false,
TOKEN_2022_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
);
const destinationToken = getAssociatedTokenAddressSync(
mint.publicKey,
recipient.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.
sourceToken, // Associated token account address to create.
feePayer.publicKey, // Owner of the associated 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.
),
createAssociatedTokenAccountInstruction(
feePayer.publicKey, // Account funding the associated token account creation.
destinationToken, // Associated token account address to create.
recipient.publicKey, // Owner of the associated 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.
),
createMintToCheckedInstruction(
mint.publicKey, // Mint account that issues the tokens.
sourceToken, // Token account receiving the newly minted tokens.
feePayer.publicKey, // Signer authorized to mint new tokens.
1, // Token amount in base units.
0, // Decimals defined on the mint.
[], // Additional multisig signers.
TOKEN_2022_PROGRAM_ID // Token program that owns the mint and token account.
)
),
[feePayer],
{ commitment: "confirmed" }
);
await sendAndConfirmTransaction(
connection,
new Transaction().add(
createPauseInstruction(
mint.publicKey, // Mint account to pause.
feePayer.publicKey, // Authority allowed to pause the mint.
[], // Additional multisig signers.
TOKEN_2022_PROGRAM_ID // Token program that owns the mint.
)
),
[feePayer],
{ commitment: "confirmed" }
);
const mintAccountAfterPause = await getMint(
connection,
mint.publicKey,
"confirmed",
TOKEN_2022_PROGRAM_ID
);
const configAfterPause = getPausableConfig(mintAccountAfterPause);
let pausedTransferFailure: string | undefined;
try {
await sendAndConfirmTransaction(
connection,
new Transaction().add(
createTransferCheckedInstruction(
sourceToken, // Token account sending the transfer.
mint.publicKey, // Mint with the pausable configuration.
destinationToken, // Token account receiving the transfer.
feePayer.publicKey, // Signer approving the transfer.
1, // Token amount in base units.
0, // Decimals defined on the mint.
[], // Additional multisig signers.
TOKEN_2022_PROGRAM_ID // Token program that processes the transfer.
)
),
[feePayer],
{ commitment: "confirmed" }
);
} catch (error: any) {
pausedTransferFailure =
error instanceof Error ? error.message : String(error);
}
if (!pausedTransferFailure) {
throw new Error("Expected the paused transfer to fail");
}
await sendAndConfirmTransaction(
connection,
new Transaction().add(
createResumeInstruction(
mint.publicKey, // Mint account to resume.
feePayer.publicKey, // Authority allowed to resume the mint.
[], // Additional multisig signers.
TOKEN_2022_PROGRAM_ID // Token program that owns the mint.
)
),
[feePayer],
{ commitment: "confirmed" }
);
await sendAndConfirmTransaction(
connection,
new Transaction().add(
createTransferCheckedInstruction(
sourceToken, // Token account sending the transfer.
mint.publicKey, // Mint with the pausable configuration.
destinationToken, // Token account receiving the transfer.
feePayer.publicKey, // Signer approving the transfer.
1, // Token amount in base units.
0, // Decimals defined on the mint.
[], // Additional multisig signers.
TOKEN_2022_PROGRAM_ID // Token program that processes the transfer.
)
),
[feePayer],
{ commitment: "confirmed" }
);
const mintAccountAfterResume = await getMint(
connection,
mint.publicKey,
"confirmed",
TOKEN_2022_PROGRAM_ID
);
const configAfterResume = getPausableConfig(mintAccountAfterResume);
console.log("\nMint Address:", mint.publicKey.toBase58());
console.log("\nConfig After Pause:", configAfterPause);
console.log("\nError From Failed Transaction:", pausedTransferFailure);
console.log("\nConfig After Resume:", configAfterResume);
Console
Click to execute the code.

Rust

Rust
use anyhow::{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::{
pausable::{instruction as pausable_ix, PausableConfig},
BaseStateWithExtensions, ExtensionType, StateWithExtensions,
},
instruction::{initialize_mint, mint_to_checked, transfer_checked},
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 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 recipient = Keypair::new();
let mint_space = ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::Pausable])?;
let mint_rent = client
.get_minimum_balance_for_rent_exemption(mint_space)
.await?;
let create_mint_transaction = Transaction::new_signed_with_payer(
&[
create_account(
&fee_payer.pubkey(), // Account funding account creation.
&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 PausableConfig.
&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.
),
pausable_ix::initialize(
&TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
&mint.pubkey(), // Mint account that stores the PausableConfig extension.
&fee_payer.pubkey(), // Authority allowed to pause and resume the mint.
)?,
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.
)?,
],
Some(&fee_payer.pubkey()),
&[&fee_payer, &mint],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&create_mint_transaction)
.await?;
let source_token = get_associated_token_address_with_program_id(
&fee_payer.pubkey(),
&mint.pubkey(),
&TOKEN_2022_PROGRAM_ID,
);
let destination_token = get_associated_token_address_with_program_id(
&recipient.pubkey(),
&mint.pubkey(),
&TOKEN_2022_PROGRAM_ID,
);
let create_token_accounts_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 associated token account.
&mint.pubkey(), // Mint for the associated token account.
&TOKEN_2022_PROGRAM_ID, // Token program that owns the token account.
),
create_associated_token_account(
&fee_payer.pubkey(), // Account funding the associated token account creation.
&recipient.pubkey(), // Owner of the associated token account.
&mint.pubkey(), // Mint for the associated token account.
&TOKEN_2022_PROGRAM_ID, // Token program that owns the token account.
),
mint_to_checked(
&TOKEN_2022_PROGRAM_ID, // Token program that owns the mint and token account.
&mint.pubkey(), // Mint account that issues the tokens.
&source_token, // Token account receiving the newly minted tokens.
&fee_payer.pubkey(), // Signer authorized to mint new tokens.
&[&fee_payer.pubkey()], // Additional multisig signers.
1, // Token amount in base units.
0, // Decimals defined on the mint.
)?,
],
Some(&fee_payer.pubkey()),
&[&fee_payer],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&create_token_accounts_transaction)
.await?;
let pause_ix = pausable_ix::pause(
&TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
&mint.pubkey(), // Mint account to pause.
&fee_payer.pubkey(), // Authority allowed to pause the mint.
&[&fee_payer.pubkey()], // Additional multisig signers.
)?;
let pause_transaction = Transaction::new_signed_with_payer(
&[pause_ix],
Some(&fee_payer.pubkey()),
&[&fee_payer],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&pause_transaction)
.await?;
let mint_data_after_pause = client.get_account(&mint.pubkey()).await?;
let mint_state_after_pause =
StateWithExtensions::<Mint>::unpack(&mint_data_after_pause.data)?;
let config_after_pause = mint_state_after_pause.get_extension::<PausableConfig>()?;
let transfer_ix = transfer_checked(
&TOKEN_2022_PROGRAM_ID, // Token program that processes the transfer.
&source_token, // Token account sending the transfer.
&mint.pubkey(), // Mint with the pausable configuration.
&destination_token, // Token account receiving the transfer.
&fee_payer.pubkey(), // Signer approving the transfer.
&[&fee_payer.pubkey()], // Additional multisig signers.
1, // Token amount in base units.
0, // Decimals defined on the mint.
)?;
let paused_transfer_transaction = Transaction::new_signed_with_payer(
&[transfer_ix.clone()],
Some(&fee_payer.pubkey()),
&[&fee_payer],
client.get_latest_blockhash().await?,
);
let paused_transfer_result = client.simulate_transaction(&paused_transfer_transaction).await?;
let paused_transfer_failure = paused_transfer_result
.value
.err
.ok_or_else(|| anyhow!("Expected the paused transfer to fail"))?;
let resume_ix = pausable_ix::resume(
&TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
&mint.pubkey(), // Mint account to resume.
&fee_payer.pubkey(), // Authority allowed to resume the mint.
&[&fee_payer.pubkey()], // Additional multisig signers.
)?;
let resume_transaction = Transaction::new_signed_with_payer(
&[resume_ix],
Some(&fee_payer.pubkey()),
&[&fee_payer],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&resume_transaction)
.await?;
let transfer_transaction = Transaction::new_signed_with_payer(
&[
transfer_checked(
&TOKEN_2022_PROGRAM_ID, // Token program that processes the transfer.
&source_token, // Token account sending the transfer.
&mint.pubkey(), // Mint with the pausable configuration.
&destination_token, // Token account receiving the transfer.
&fee_payer.pubkey(), // Signer approving the transfer.
&[&fee_payer.pubkey()], // Additional multisig signers.
1, // Token amount in base units.
0, // Decimals defined on the mint.
)?,
],
Some(&fee_payer.pubkey()),
&[&fee_payer],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&transfer_transaction)
.await?;
let mint_data_after_resume = client.get_account(&mint.pubkey()).await?;
let mint_state_after_resume =
StateWithExtensions::<Mint>::unpack(&mint_data_after_resume.data)?;
let config_after_resume = mint_state_after_resume.get_extension::<PausableConfig>()?;
println!("\nMint Address: {}", mint.pubkey());
println!("\nConfig After Pause: {:#?}", config_after_pause);
println!("\nError From Failed Transaction: {:?}", paused_transfer_failure);
println!("\nConfig After Resume: {:#?}", config_after_resume);
Ok(())
}
Console
Click to execute the code.

Is this page helpful?

目次

ページを編集

管理運営

© 2026 Solana Foundation.
無断転載を禁じます。
つながろう