権限の設定

トークン権限の理解

ミントアカウントの権限

  • ミント権限: 新しいトークンの作成を制御します。任意のトークンアカウントにトークンをミントできます。固定供給トークンを作成するために、初期供給が作成された後に取り消されることが多いです。
  • 凍結権限: トークンアカウントを凍結および解凍する能力を制御します。トークンアカウントがトークンを転送するのを防ぐことができます。ユーザーのトークンが凍結されないことを保証するために、しばしば取り消されます。

トークンアカウントの権限

  • アカウント所有者: トークンアカウントを完全に制御します。トークンの転送、トークンの焼却、委任者の承認、残高がゼロの場合のアカウントの閉鎖ができます。
  • 閉鎖権限: 残高がゼロの場合にトークンアカウントを閉鎖できます。デフォルトではこれはアカウント所有者ですが、別のアカウントに委任することができます。

権限の設定方法

SetAuthority instructionsはミントとトークンアカウントの権限を変更または取り消します。現在の権限者のみが、新しいアドレスに権限を移譲したり、権限をnullに設定して永久に取り消したりすることができます。一度取り消された権限は復元できません。

トークンプログラムトークン拡張プログラムは同じ機能を実現するために類似の実装を共有しています。

Typescript

import {
airdropFactory,
appendTransactionMessageInstructions,
createSolanaRpc,
createSolanaRpcSubscriptions,
createTransactionMessage,
generateKeyPairSigner,
getSignatureFromTransaction,
lamports,
pipe,
sendAndConfirmTransactionFactory,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
signTransactionMessageWithSigners
} from "@solana/kit";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
getInitializeMintInstruction,
getMintSize,
TOKEN_PROGRAM_ADDRESS,
findAssociatedTokenPda,
getCreateAssociatedTokenInstructionAsync,
getSetAuthorityInstruction,
AuthorityType
} from "@solana-program/token";
// Create Connection, local validator in this example
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate keypairs for fee payer and new authority
const feePayer = await generateKeyPairSigner();
const newAuthority = await generateKeyPairSigner();
// Fund fee payer
await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: feePayer.address,
lamports: lamports(1_000_000_000n),
commitment: "confirmed"
});
// Generate keypair to use as address of mint
const mint = await generateKeyPairSigner();
// Get default mint account size (in bytes), no extensions enabled
const space = BigInt(getMintSize());
// Get minimum balance for rent exemption
const rent = await rpc.getMinimumBalanceForRentExemption(space).send();
// Get latest blockhash to include in transaction
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
// Instruction to create new account for mint (token program)
// Invokes the system program
const createAccountInstruction = getCreateAccountInstruction({
payer: feePayer,
newAccount: mint,
lamports: rent,
space,
programAddress: TOKEN_PROGRAM_ADDRESS
});
// Instruction to initialize mint account data
// Invokes the token program
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 9,
mintAuthority: feePayer.address,
freezeAuthority: feePayer.address
});
// Use findAssociatedTokenPda to derive the ATA address
const [associatedTokenAddress] = await findAssociatedTokenPda({
mint: mint.address,
owner: feePayer.address,
tokenProgram: TOKEN_PROGRAM_ADDRESS
});
// Create instruction to create the associated token account
const createAtaInstruction = await getCreateAssociatedTokenInstructionAsync({
payer: feePayer,
mint: mint.address,
owner: feePayer.address
});
const instructions = [
createAccountInstruction,
initializeMintInstruction,
createAtaInstruction
];
// Create transaction message
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(feePayer, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstructions(instructions, tx)
);
// Sign transaction message with all required signers
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
// Send and confirm transaction
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedTransaction,
{ commitment: "confirmed" }
);
// Get transaction signature
const transactionSignature = getSignatureFromTransaction(signedTransaction);
console.log("\nMint Address:", mint.address.toString());
console.log("New Authority Address:", newAuthority.address.toString());
console.log(
"Associated Token Account Address:",
associatedTokenAddress.toString()
);
console.log("\nTransaction Signature:", transactionSignature);
// Get a fresh blockhash for the authority change transaction
const { value: authorityBlockhash } = await rpc.getLatestBlockhash().send();
// 1. Change Mint Authority (MintTokens)
const setMintAuthorityIx = getSetAuthorityInstruction({
owned: mint.address,
owner: feePayer,
authorityType: AuthorityType.MintTokens,
newAuthority: newAuthority.address
});
// 2. Change Freeze Authority (FreezeAccount)
const setFreezeAuthorityIx = getSetAuthorityInstruction({
owned: mint.address,
owner: feePayer,
authorityType: AuthorityType.FreezeAccount,
newAuthority: newAuthority.address
});
// Create transaction message for authority changes
const authorityTxMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(feePayer, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(authorityBlockhash, tx),
(tx) =>
appendTransactionMessageInstructions(
[setMintAuthorityIx, setFreezeAuthorityIx],
tx
)
);
// Sign transaction message with all required signers
const signedAuthorityTx =
await signTransactionMessageWithSigners(authorityTxMessage);
// Send and confirm transaction
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedAuthorityTx,
{ commitment: "confirmed" }
);
// Get transaction signature
const transactionSignature2 = getSignatureFromTransaction(signedAuthorityTx);
console.log("\nSuccessfully changed mint and freeze authorities");
console.log("Transaction Signature:", transactionSignature2);
// Get a fresh blockhash for the revoke transaction
const { value: revokeBlockhash } = await rpc.getLatestBlockhash().send();
// 3. Example of revoking authority (setting to null)
const revokeMintAuthorityIx = getSetAuthorityInstruction({
owned: mint.address,
owner: newAuthority,
authorityType: AuthorityType.MintTokens,
newAuthority: null
});
// Create transaction message for revoking
const revokeTxMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(feePayer, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(revokeBlockhash, tx),
(tx) => appendTransactionMessageInstructions([revokeMintAuthorityIx], tx)
);
// Sign transaction message with all required signers (newAuthority needs to sign)
const signedRevokeTx = await signTransactionMessageWithSigners(revokeTxMessage);
// Send and confirm transaction
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedRevokeTx,
{ commitment: "confirmed" }
);
// Get transaction signature
const transactionSignature3 = getSignatureFromTransaction(signedRevokeTx);
console.log("\nSuccessfully revoked mint authority");
console.log("Transaction Signature:", transactionSignature3);
Console
Click to execute the code.

Rust

use anyhow::Result;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::{
commitment_config::CommitmentConfig,
program_pack::Pack,
signature::{Keypair, Signer},
system_instruction::create_account,
transaction::Transaction,
};
use spl_associated_token_account::{
get_associated_token_address_with_program_id, instruction::create_associated_token_account,
};
use spl_token::{
id as token_program_id,
instruction::{initialize_mint, set_authority, AuthorityType},
state::Mint,
};
#[tokio::main]
async fn main() -> Result<()> {
// Create connection to local validator
let client = RpcClient::new_with_commitment(
String::from("http://localhost:8899"),
CommitmentConfig::confirmed(),
);
let latestBlockhash = client.get_latest_blockhash().await?;
// Generate a new keypair for the fee payer
let fee_payer = Keypair::new();
// Generate a new keypair for the new authority
let new_authority = Keypair::new();
// Airdrop 1 SOL to fee payer
let airdrop_signature = client
.request_airdrop(&fee_payer.pubkey(), 1_000_000_000)
.await?;
client.confirm_transaction(&airdrop_signature).await?;
loop {
let confirmed = client.confirm_transaction(&airdrop_signature).await?;
if confirmed {
break;
}
}
// Generate keypair to use as address of mint
let mint = Keypair::new();
// Get default mint account size (in bytes), no extensions enabled
let mint_space = Mint::LEN;
let mint_rent = client
.get_minimum_balance_for_rent_exemption(mint_space)
.await?;
// Instruction to create new account for mint (token program)
let create_account_instruction = create_account(
&fee_payer.pubkey(), // payer
&mint.pubkey(), // new account (mint)
mint_rent, // lamports
mint_space as u64, // space
&token_program_id(), // program id
);
// Instruction to initialize mint account data
let initialize_mint_instruction = initialize_mint(
&token_program_id(),
&mint.pubkey(), // mint
&fee_payer.pubkey(), // mint authority
Some(&fee_payer.pubkey()), // freeze authority
9, // decimals
)?;
// Calculate the associated token account address for fee_payer
let associated_token_address = get_associated_token_address_with_program_id(
&fee_payer.pubkey(), // owner
&mint.pubkey(), // mint
&token_program_id(), // program_id
);
// Instruction to create associated token account
let create_ata_instruction = create_associated_token_account(
&fee_payer.pubkey(), // funding address
&fee_payer.pubkey(), // wallet address
&mint.pubkey(), // mint address
&token_program_id(), // program id
);
// Create transaction and add instructions
let transaction = Transaction::new_signed_with_payer(
&[
create_account_instruction,
initialize_mint_instruction,
create_ata_instruction,
],
Some(&fee_payer.pubkey()),
&[&fee_payer, &mint],
latestBlockhash,
);
// Send and confirm transaction
let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;
println!("Mint Address: {}", mint.pubkey());
println!("New Authority Address: {}", new_authority.pubkey());
println!(
"Associated Token Account Address: {}",
associated_token_address
);
println!("Transaction Signature: {}", transaction_signature);
// Get the latest blockhash for the authority change transaction
let latestBlockhash = client.get_latest_blockhash().await?;
// 1. Change Mint Authority (MintTokens)
let set_mint_authority_ix = set_authority(
&token_program_id(), // program id
&mint.pubkey(), // mint account
Some(&new_authority.pubkey()), // new authority
AuthorityType::MintTokens, // authority type
&fee_payer.pubkey(), // current authority
&[&fee_payer.pubkey()], // signers
)?;
// 2. Change Freeze Authority (FreezeAccount)
let set_freeze_authority_ix = set_authority(
&token_program_id(), // program id
&mint.pubkey(), // mint account
Some(&new_authority.pubkey()), // new authority
AuthorityType::FreezeAccount, // authority type
&fee_payer.pubkey(), // current authority
&[&fee_payer.pubkey()], // signers
)?;
// Create transaction for authority changes
let transaction = Transaction::new_signed_with_payer(
&[set_mint_authority_ix, set_freeze_authority_ix],
Some(&fee_payer.pubkey()),
&[&fee_payer],
latestBlockhash,
);
// Send and confirm transaction
let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;
println!(
"\nSuccessfully changed mint and freeze authorities to: {}",
new_authority.pubkey()
);
println!("Transaction Signature: {}", transaction_signature);
// Get the latest blockhash for the revoke transaction
let latestBlockhash = client.get_latest_blockhash().await?;
// 3. Example of revoking authority (setting to null)
let revoke_mint_authority_ix = set_authority(
&token_program_id(), // program id
&mint.pubkey(), // mint account
None, // new authority (None to revoke)
AuthorityType::MintTokens, // authority type
&new_authority.pubkey(), // current authority
&[&new_authority.pubkey()], // signers
)?;
// Create transaction for revoking
let transaction = Transaction::new_signed_with_payer(
&[revoke_mint_authority_ix],
Some(&fee_payer.pubkey()),
&[&fee_payer, &new_authority], // new_authority needs to sign
latestBlockhash,
);
// Send and confirm transaction
let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;
println!("\nSuccessfully revoked mint authority");
println!("Transaction Signature: {}", transaction_signature);
Ok(())
}
Console
Click to execute the code.

Is this page helpful?

目次

ページを編集