Μόνιμος Αντιπρόσωπος

Τι Είναι ένας Μόνιμος Εκπρόσωπος;

Η επέκταση mint PermanentDelegate του Token Extension Program εκχωρεί μια εξουσία εκπροσώπου στο ίδιο το mint.

Ένας μόνιμος εκπρόσωπος είναι μια εξουσία σε επίπεδο mint που μπορεί να εξουσιοδοτεί μεταφορές και καταστροφές για οποιονδήποτε token account για αυτό το mint. Λειτουργεί ως καθολικός εκπρόσωπος για όλους τους token accounts για το mint, και οι κάτοχοι token account δεν μπορούν να ανακαλέσουν τον μόνιμο εκπρόσωπο από τους token accounts τους.

Η εξουσία του mint μπορεί επίσης να αλλάξει τον μόνιμο εκπρόσωπο αργότερα με την SetAuthority χρησιμοποιώντας την AuthorityType::PermanentDelegate.

Πώς να Δημιουργήσετε και να Χρησιμοποιήσετε έναν Μόνιμο Εκπρόσωπο

Για να δημιουργήσετε και να χρησιμοποιήσετε έναν μόνιμο εκπρόσωπο:

  1. Υπολογίστε το μέγεθος του λογαριασμού mint και το rent που απαιτείται για το mint και την επέκταση PermanentDelegate.
  2. Δημιουργήστε τον λογαριασμό mint με την CreateAccount, αρχικοποιήστε την PermanentDelegate, και αρχικοποιήστε το mint με την InitializeMint.
  3. Υποβάλετε την TransferChecked ή την BurnChecked υπογεγραμμένη από τον μόνιμο εκπρόσωπο. Το Token Program επεξεργάζεται αυτές τις οδηγίες με τον ίδιο τρόπο όπως εάν ο κάτοχος του token account τις είχε υπογράψει.

Υπολογισμός μεγέθους λογαριασμού

Υπολογίστε το μέγεθος του λογαριασμού mint για το βασικό mint συν την επέκταση PermanentDelegate. Αυτό είναι το μέγεθος που χρησιμοποιείται στην CreateAccount.

Υπολογισμός rent

Υπολογίστε το rent χρησιμοποιώντας το μέγεθος που απαιτείται για το mint συν την επέκταση PermanentDelegate.

Δημιουργία του λογαριασμού mint

Δημιουργήστε το mint account με τον υπολογισμένο χώρο και τα lamports.

Αρχικοποίηση PermanentDelegate

Αρχικοποιήστε την επέκταση PermanentDelegate στο mint.

Αρχικοποίηση του mint

Αρχικοποιήστε το mint με InitializeMint στην ίδια συναλλαγή.

Δημιουργία token accounts και έκδοση tokens

Δημιουργήστε token accounts για τον κάτοχο και τον παραλήπτη, στη συνέχεια εκδώστε tokens στο token account του κατόχου.

Μεταφορά με τον μόνιμο αντιπρόσωπο

Μεταφέρετε tokens με TransferChecked υπογεγραμμένο από τον μόνιμο αντιπρόσωπο.

Υπολογισμός μεγέθους λογαριασμού

Υπολογίστε το μέγεθος του λογαριασμού mint για το βασικό mint συν την επέκταση PermanentDelegate. Αυτό είναι το μέγεθος που χρησιμοποιείται στην CreateAccount.

Υπολογισμός rent

Υπολογίστε το rent χρησιμοποιώντας το μέγεθος που απαιτείται για το mint συν την επέκταση PermanentDelegate.

Δημιουργία του λογαριασμού mint

Δημιουργήστε το mint account με τον υπολογισμένο χώρο και τα lamports.

Αρχικοποίηση PermanentDelegate

Αρχικοποιήστε την επέκταση PermanentDelegate στο mint.

Αρχικοποίηση του mint

Αρχικοποιήστε το mint με InitializeMint στην ίδια συναλλαγή.

Δημιουργία token accounts και έκδοση tokens

Δημιουργήστε token accounts για τον κάτοχο και τον παραλήπτη, στη συνέχεια εκδώστε tokens στο token account του κατόχου.

Μεταφορά με τον μόνιμο αντιπρόσωπο

Μεταφέρετε tokens με TransferChecked υπογεγραμμένο από τον μόνιμο αντιπρόσωπο.

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 owner = await generateKeyPairSigner();
const delegate = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
const permanentDelegateExtension = extension("PermanentDelegate", {
delegate: delegate.address
});
const mintSpace = BigInt(getMintSize([permanentDelegateExtension]));

Σειρά Εντολών

Η InitializePermanentDelegate πρέπει να προηγείται της InitializeMint. Οι CreateAccount, InitializePermanentDelegate και InitializeMint πρέπει να περιλαμβάνονται στην ίδια συναλλαγή.

Αναφορά Πηγής

ΣτοιχείοΠεριγραφήΠηγή
PermanentDelegateΕπέκταση mint που αποθηκεύει τον εξουσιοδοτημένο αντιπρόσωπο σε κάθε token account για το mint.Πηγή
InitializePermanentDelegateΕντολή που αρχικοποιεί τον μόνιμο αντιπρόσωπο πριν από την InitializeMint.Πηγή
SetAuthorityΒασική εντολή token που χρησιμοποιείται με την AuthorityType::PermanentDelegate για την εναλλαγή του αντιπροσώπου.Πηγή
AuthorityType::PermanentDelegateΔιακριτικό εξουσιοδότησης που χρησιμοποιείται με την SetAuthority για την εναλλαγή του μόνιμου αντιπροσώπου σε ένα mint.Πηγή
process_initialize_permanent_delegateΛογική επεξεργαστή που γράφει την επέκταση μόνιμου αντιπροσώπου στο mint.Πηγή
process_set_authorityΛογική επεξεργαστή που επικυρώνει και εναλλάσσει τον μόνιμο αντιπρόσωπο όταν χρησιμοποιείται η AuthorityType::PermanentDelegate.Πηγή

Typescript

Το παράδειγμα Kit παρακάτω χρησιμοποιεί απευθείας τις δημιουργημένες εντολές. Παλαιότερα παραδείγματα που χρησιμοποιούν τις @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,
fetchToken,
findAssociatedTokenPda,
getCreateAssociatedTokenInstructionAsync,
getInitializeMintInstruction,
getInitializePermanentDelegateInstruction,
getMintSize,
getMintToCheckedInstruction,
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 owner = await generateKeyPairSigner();
const delegate = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
const permanentDelegateExtension = extension("PermanentDelegate", {
delegate: delegate.address
});
const mintSpace = BigInt(getMintSize([permanentDelegateExtension]));
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 PermanentDelegate.
programAddress: TOKEN_2022_PROGRAM_ADDRESS // Program that owns the mint account.
}),
getInitializePermanentDelegateInstruction({
mint: mint.address, // Mint account that stores the PermanentDelegate extension.
delegate: delegate.address // Permanent delegate authorized for all token accounts for 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: owner.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: owner.address // Owner of the source 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 destination 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([
getTransferCheckedInstruction({
source: sourceToken, // Token account sending the transfer.
mint: mint.address, // Mint with the permanent delegate configuration.
destination: destinationToken, // Token account receiving the transfer.
authority: delegate, // Permanent delegate signing the transfer.
amount: 1n, // Token amount in base units.
decimals: 0 // Decimals defined on the mint.
})
]);
const destinationAccount = await fetchToken(client.rpc, destinationToken);
const mintAccount = await fetchMint(client.rpc, mint.address);
const permanentDelegate = (
unwrapOption(mintAccount.data.extensions) ?? []
).find((item) => isExtension("PermanentDelegate", item));
console.log("Mint Address:", mint.address);
console.log("Destination Amount:", destinationAccount.data.amount);
console.log("Permanent Delegate Extension:", permanentDelegate);
Console
Click to execute the code.

Web3.js

Instructions
import {
Connection,
Keypair,
sendAndConfirmTransaction,
SystemProgram,
Transaction,
LAMPORTS_PER_SOL
} from "@solana/web3.js";
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
createAssociatedTokenAccountInstruction,
createInitializeMintInstruction,
createInitializePermanentDelegateInstruction,
createMintToCheckedInstruction,
createTransferCheckedInstruction,
ExtensionType,
getAccount,
getAssociatedTokenAddressSync,
getMint,
getMintLen,
getPermanentDelegate,
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 owner = Keypair.generate();
const delegate = 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 extensions = [ExtensionType.PermanentDelegate];
const mint = Keypair.generate();
const mintLength = getMintLen(extensions);
const mintRent = await connection.getMinimumBalanceForRentExemption(mintLength);
const sourceToken = getAssociatedTokenAddressSync(
mint.publicKey,
owner.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
);
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 PermanentDelegate.
lamports: mintRent, // Lamports funding the mint account rent.
programId: TOKEN_2022_PROGRAM_ID // Program that owns the mint account.
});
const initializePermanentDelegateInstruction =
createInitializePermanentDelegateInstruction(
mint.publicKey, // Mint account that stores the PermanentDelegate extension.
delegate.publicKey, // Permanent delegate authorized for all token accounts for the mint.
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().add(
createMintAccountInstruction,
initializePermanentDelegateInstruction,
initializeMintInstruction
),
[feePayer, mint],
{
commitment: "confirmed"
}
);
await sendAndConfirmTransaction(
connection,
new Transaction().add(
createAssociatedTokenAccountInstruction(
feePayer.publicKey, // Account funding the associated token account creation.
sourceToken, // Associated token account address to create.
owner.publicKey, // Owner of the source 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 destination 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(
createTransferCheckedInstruction(
sourceToken, // Token account sending the transfer.
mint.publicKey, // Mint with the permanent delegate configuration.
destinationToken, // Token account receiving the transfer.
delegate.publicKey, // Permanent delegate signing 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, delegate],
{
commitment: "confirmed"
}
);
const destinationAccount = await getAccount(
connection,
destinationToken,
"confirmed",
TOKEN_2022_PROGRAM_ID
);
const mintAccount = await getMint(
connection,
mint.publicKey,
"confirmed",
TOKEN_2022_PROGRAM_ID
);
const permanentDelegate = getPermanentDelegate(mintAccount);
console.log("Mint Address:", mint.publicKey.toBase58());
console.log("Destination Amount:", destinationAccount.amount.toString());
console.log("Permanent Delegate Extension:", permanentDelegate);
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::{
permanent_delegate::PermanentDelegate, BaseStateWithExtensions, ExtensionType,
StateWithExtensions,
},
instruction::{
initialize_mint, initialize_permanent_delegate, mint_to_checked, transfer_checked,
},
state::{Account, 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 owner = Keypair::new();
let delegate = Keypair::new();
let recipient = 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::PermanentDelegate])?;
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 PermanentDelegate.
&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.
);
let initialize_permanent_delegate_ix = initialize_permanent_delegate(
&TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
&mint.pubkey(), // Mint account that stores the PermanentDelegate extension.
&delegate.pubkey(), // Permanent delegate authorized for all token accounts for the mint.
)?;
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_permanent_delegate_ix,
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 source_token = get_associated_token_address_with_program_id(
&owner.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.
&owner.pubkey(), // Owner of the source 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 destination 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 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 permanent delegate configuration.
&destination_token, // Token account receiving the transfer.
&delegate.pubkey(), // Permanent delegate signing the transfer.
&[&delegate.pubkey()], // Additional multisig signers.
1, // Token amount in base units.
0, // Decimals defined on the mint.
)?,
],
Some(&fee_payer.pubkey()),
&[&fee_payer, &delegate],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&transfer_transaction)
.await?;
let destination_account = client.get_account(&destination_token).await?;
let destination_state =
StateWithExtensions::<Account>::unpack(&destination_account.data)?;
let mint_account = client.get_account(&mint.pubkey()).await?;
let mint_state = StateWithExtensions::<Mint>::unpack(&mint_account.data)?;
let permanent_delegate = mint_state.get_extension::<PermanentDelegate>()?;
println!("Mint Address: {}", mint.pubkey());
println!(
"Destination Amount: {}",
u64::from(destination_state.base.amount)
);
println!("Permanent Delegate Extension: {:?}", permanent_delegate);
Ok(())
}
Console
Click to execute the code.

Is this page helpful?

Πίνακας Περιεχομένων

Επεξεργασία Σελίδας

Διαχειρίζεται από

© 2026 Ίδρυμα Solana.
Με επιφύλαξη παντός δικαιώματος.
Συνδεθείτε