Token non trasferibili

Come abilitare l'estensione InitializeNonTransferableMint

L' InitializeNonTransferableMint impedisce ai token di essere trasferiti tra token account dopo il minting. Una volta creati, i token rimangono permanentemente nel token account. Tuttavia, il proprietario del token account può ancora bruciare token e chiudere il token account quando il saldo raggiunge zero.

Typescript

import { getCreateAccountInstruction } from "@solana-program/system";
import {
extension,
findAssociatedTokenPda,
getCreateAssociatedTokenInstructionAsync,
getInitializeMintInstruction,
getInitializeNonTransferableMintInstruction,
getMintSize,
getTokenSize,
TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";
import {
airdropFactory,
appendTransactionMessageInstructions,
createSolanaRpc,
createSolanaRpcSubscriptions,
createTransactionMessage,
generateKeyPairSigner,
getSignatureFromTransaction,
lamports,
pipe,
sendAndConfirmTransactionFactory,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
signTransactionMessageWithSigners
} from "@solana/kit";
// Create Connection, local validator in this example
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate the authority for the mint (also acts as fee payer)
const authority = await generateKeyPairSigner();
// Fund authority/fee payer
await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: authority.address,
lamports: lamports(5_000_000_000n), // 5 SOL
commitment: "confirmed"
});
// Generate keypair to use as address of mint
const mint = await generateKeyPairSigner();
// Define the non-transferrable extension
const nonTransferableExtension = extension("NonTransferable", {});
// Get mint account size with non-transferrable extension
const space = BigInt(getMintSize([nonTransferableExtension]));
// 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 createMintAccountInstruction = getCreateAccountInstruction({
payer: authority,
newAccount: mint,
lamports: rent,
space,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
});
// Instruction to initialize non-transferrable extension
const initializeNonTransferableInstruction =
getInitializeNonTransferableMintInstruction({
mint: mint.address
});
// Instruction to initialize mint account data
// Invokes the token22 program
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 0, // Often 0 for non-transferrable tokens like certificates/badges
mintAuthority: authority.address,
freezeAuthority: authority.address
});
// Use findAssociatedTokenPda to derive the ATA address
const [associatedTokenAddress] = await findAssociatedTokenPda({
mint: mint.address,
owner: authority.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
// instruction to create the associated token account for the authority
const createAtaInstruction = await getCreateAssociatedTokenInstructionAsync({
payer: authority,
mint: mint.address,
owner: authority.address
});
const instructions = [
createMintAccountInstruction,
initializeNonTransferableInstruction,
initializeMintInstruction,
createAtaInstruction
];
// Create transaction message
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(authority, 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", skipPreflight: true }
);
// Get transaction signature
const transactionSignature = getSignatureFromTransaction(signedTransaction);
console.log("Mint Address with Non-Transferrable Extension:", mint.address);
console.log("ATA Address:", associatedTokenAddress);
console.log(
"Note: Tokens minted from this mint cannot be transferred between accounts"
);
console.log("Mint Authority:", authority.address);
console.log("Transaction Signature:", transactionSignature);
Console
Click to execute the code.

Rust

use anyhow::Result;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::{
commitment_config::CommitmentConfig,
signature::{Keypair, Signer},
system_instruction::create_account,
transaction::Transaction,
};
use spl_associated_token_account::get_associated_token_address;
use spl_associated_token_account::instruction::create_associated_token_account;
use spl_token_2022::{
ID as TOKEN_2022_PROGRAM_ID,
extension::ExtensionType,
instruction::{initialize_mint, initialize_non_transferable_mint},
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 latest_blockhash = client.get_latest_blockhash().await?;
// Generate a new keypair for the fee payer
let fee_payer = Keypair::new();
// Airdrop 5 SOL to fee payer
let airdrop_signature = client
.request_airdrop(&fee_payer.pubkey(), 5_000_000_000)
.await?;
client.confirm_transaction(&airdrop_signature).await?;
// Ensure the airdrop is confirmed
loop {
let confirmed = client.confirm_transaction(&airdrop_signature).await?;
if confirmed {
break;
}
}
// Generate keypair to use as address of mint
let mint = Keypair::new();
// Calculate mint account size with non-transferrable extension
let mint_space =
ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::NonTransferable])?;
let mint_rent = client
.get_minimum_balance_for_rent_exemption(mint_space)
.await?;
// Instruction to create new account for mint (token22)
let create_mint_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_non_transferable_instruction =
initialize_non_transferable_mint(&TOKEN_2022_PROGRAM_ID, &mint.pubkey())?;
// Instruction to initialize mint account data
let initialize_mint_instruction = initialize_mint(
&TOKEN_2022_PROGRAM_ID, // program id
&mint.pubkey(), // mint
&fee_payer.pubkey(), // mint authority
Some(&fee_payer.pubkey()), // freeze authority
0, // decimals - often 0 for non-transferrable tokens like certificates/badges
)?;
// Get associated token account address
let associated_token_address = get_associated_token_address(
&fee_payer.pubkey(), // owner
&mint.pubkey(), // mint
);
// Instruction to create associated token account
let create_ata_instruction = create_associated_token_account(
&fee_payer.pubkey(), // payer
&fee_payer.pubkey(), // owner
&mint.pubkey(), // mint
&TOKEN_2022_PROGRAM_ID, // token program
);
// Construct transaction with non-transferrable mint extension
let transaction = Transaction::new_signed_with_payer(
&[
create_mint_account_instruction,
initialize_non_transferable_instruction,
initialize_mint_instruction,
create_ata_instruction,
],
Some(&fee_payer.pubkey()),
&[&fee_payer, &mint],
latest_blockhash,
);
// Send and confirm transaction
let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;
println!(
"Mint Address with Non-Transferrable Extension: {}",
mint.pubkey()
);
println!("ATA Address: {}", associated_token_address);
println!("Note: Tokens minted from this mint cannot be transferred between accounts");
println!("Mint Authority: {}", fee_payer.pubkey());
println!("Transaction Signature: {}", transaction_signature);
Ok(())
}
Console
Click to execute the code.

Is this page helpful?

Indice

Modifica Pagina