Разрешённое сжигание

Что такое разрешённое сжигание?

Расширение минта PermissionedBurnConfig Token Extensions Program требует, чтобы настроенный орган сжигания совместно подписывал каждое сжигание для данного минта.

Пока установлен орган сжигания:

  • Стандартные инструкции Burn и BurnChecked завершаются с ошибкой TokenError::InvalidInstruction.
  • Для сжигания необходимо использовать PermissionedBurnInstruction::Burn или PermissionedBurnInstruction::BurnChecked, подписанные как органом сжигания, так и владельцем или делегатом token account.

Орган сжигания является совместным подписантом, а не заменой владельца. Орган сжигания в одиночку не может сжигать токены из чужого token account, а владелец token account не может сжигать токены без подписи органа сжигания. Постоянный делегат также обязан использовать инструкции разрешённого сжигания и по-прежнему нуждается в совместной подписи органа сжигания.

Это позволяет эмитенту поддерживать синхронизацию эмиссии токенов с внебиржевыми записями — например, для токенизированного актива, который должен оставаться обеспеченным в соотношении 1:1, — предотвращая односторонне сжигание токенов держателями.

Орган сжигания может быть позднее заменён с помощью SetAuthority, используя AuthorityType::PermissionedBurn. Установка органа в None отключает разрешённое сжигание и повторно включает стандартные инструкции сжигания. Данные самого расширения остаются на минте.

Доступность

Разрешённое сжигание включено в Token-2022 program@v11.0.0. Сегодня оно доступно в devnet и запланировано к включению в mainnet в июне 2026 года. Token Extension Program развёртывается отдельно для каждого кластера, поэтому убедитесь, что развёртывание на целевом кластере включает версию v11.0.0 или новее.

Локальный тестовый validator также включает более старую сборку Token-2022, поэтому для запуска примеров на этой странице загрузите программу v11.0.0 из devnet в ваш тестовый validator:

Terminal
solana program dump -u devnet TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb token_2022.so
solana-test-validator --reset --bpf-program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb token_2022.so

Как создать Mint с разрешённым сжиганием

Чтобы создать mint с разрешённым сжиганием и сжечь токены:

  1. Вычислите размер mint account и необходимый rent для mint и расширения PermissionedBurnConfig.
  2. Создайте mint account с помощью CreateAccount, инициализируйте PermissionedBurnConfig и инициализируйте mint с помощью InitializeMint.
  3. Создайте token account и выпустите токены.
  4. Выполните сжигание с помощью PermissionedBurnInstruction::BurnChecked, подписанного как владельцем token account, так и burn authority.
  5. При необходимости отключите разрешённое сжигание с помощью SetAuthority, используя AuthorityType::PermissionedBurn и authority None, что повторно включает стандартные инструкции сжигания. Полные примеры кода ниже демонстрируют этот шаг.

Вычисление размера аккаунта

Вычислите размер mint account для базового mint плюс расширение PermissionedBurnConfig. Этот размер используется в CreateAccount.

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 burnAuthority = await generateKeyPairSigner();
const permissionedBurnExtension = extension("PermissionedBurn", {
authority: burnAuthority.address
});
const mintSpace = BigInt(getMintSize([permissionedBurnExtension]));

Вычисление rent

Вычислите rent, используя размер, необходимый для mint плюс расширение PermissionedBurnConfig.

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 burnAuthority = await generateKeyPairSigner();
const permissionedBurnExtension = extension("PermissionedBurn", {
authority: burnAuthority.address
});
const mintSpace = BigInt(getMintSize([permissionedBurnExtension]));
const mintRent = await client.rpc
.getMinimumBalanceForRentExemption(mintSpace)
.send();

Создание mint account

Создайте mint account с вычисленными пространством и lamports.

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 burnAuthority = await generateKeyPairSigner();
const permissionedBurnExtension = extension("PermissionedBurn", {
authority: burnAuthority.address
});
const mintSpace = BigInt(getMintSize([permissionedBurnExtension]));
const mintRent = await client.rpc
.getMinimumBalanceForRentExemption(mintSpace)
.send();
await client.sendTransaction([
getCreateAccountInstruction({
payer: client.payer,
newAccount: mint,
lamports: mintRent,
space: mintSpace,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
})
]);

Инициализация PermissionedBurn

Инициализируйте расширение PermissionedBurnConfig на mint с burn authority.

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 burnAuthority = await generateKeyPairSigner();
const permissionedBurnExtension = extension("PermissionedBurn", {
authority: burnAuthority.address
});
const mintSpace = BigInt(getMintSize([permissionedBurnExtension]));
const mintRent = await client.rpc
.getMinimumBalanceForRentExemption(mintSpace)
.send();
await client.sendTransaction([
getCreateAccountInstruction({
payer: client.payer,
newAccount: mint,
lamports: mintRent,
space: mintSpace,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
}),
getInitializePermissionedBurnInstruction({
mint: mint.address,
authority: burnAuthority.address
})
]);

Инициализация mint

Инициализируйте mint с помощью InitializeMint в той же транзакции.

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 burnAuthority = await generateKeyPairSigner();
const permissionedBurnExtension = extension("PermissionedBurn", {
authority: burnAuthority.address
});
const mintSpace = BigInt(getMintSize([permissionedBurnExtension]));
const mintRent = await client.rpc
.getMinimumBalanceForRentExemption(mintSpace)
.send();
await client.sendTransaction([
getCreateAccountInstruction({
payer: client.payer,
newAccount: mint,
lamports: mintRent,
space: mintSpace,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
}),
getInitializePermissionedBurnInstruction({
mint: mint.address,
authority: burnAuthority.address
}),
getInitializeMintInstruction({
mint: mint.address,
decimals: 0,
mintAuthority: client.payer.address,
freezeAuthority: client.payer.address
})
]);

Создать token account и выпустить токены

Создайте token account для плательщика и выпустите на него токены.

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 burnAuthority = await generateKeyPairSigner();
const permissionedBurnExtension = extension("PermissionedBurn", {
authority: burnAuthority.address
});
const mintSpace = BigInt(getMintSize([permissionedBurnExtension]));
const mintRent = await client.rpc
.getMinimumBalanceForRentExemption(mintSpace)
.send();
await client.sendTransaction([
getCreateAccountInstruction({
payer: client.payer,
newAccount: mint,
lamports: mintRent,
space: mintSpace,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
}),
getInitializePermissionedBurnInstruction({
mint: mint.address,
authority: burnAuthority.address
}),
getInitializeMintInstruction({
mint: mint.address,
decimals: 0,
mintAuthority: client.payer.address,
freezeAuthority: client.payer.address
})
]);
const [sourceToken] = await findAssociatedTokenPda({
mint: mint.address,
owner: client.payer.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
await client.sendTransaction([
await getCreateAssociatedTokenInstructionAsync({
payer: client.payer,
mint: mint.address,
owner: client.payer.address
}),
getMintToCheckedInstruction({
mint: mint.address,
token: sourceToken,
mintAuthority: client.payer,
amount: 2n,
decimals: 0
})
]);

Сжечь с использованием полномочий сжигания

Сожгите токены с помощью PermissionedBurnInstruction::BurnChecked, подписанного как владельцем token account, так и органом полномочий сжигания.

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 burnAuthority = await generateKeyPairSigner();
const permissionedBurnExtension = extension("PermissionedBurn", {
authority: burnAuthority.address
});
const mintSpace = BigInt(getMintSize([permissionedBurnExtension]));
const mintRent = await client.rpc
.getMinimumBalanceForRentExemption(mintSpace)
.send();
await client.sendTransaction([
getCreateAccountInstruction({
payer: client.payer,
newAccount: mint,
lamports: mintRent,
space: mintSpace,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
}),
getInitializePermissionedBurnInstruction({
mint: mint.address,
authority: burnAuthority.address
}),
getInitializeMintInstruction({
mint: mint.address,
decimals: 0,
mintAuthority: client.payer.address,
freezeAuthority: client.payer.address
})
]);
const [sourceToken] = await findAssociatedTokenPda({
mint: mint.address,
owner: client.payer.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
await client.sendTransaction([
await getCreateAssociatedTokenInstructionAsync({
payer: client.payer,
mint: mint.address,
owner: client.payer.address
}),
getMintToCheckedInstruction({
mint: mint.address,
token: sourceToken,
mintAuthority: client.payer,
amount: 2n,
decimals: 0
})
]);
await client.sendTransaction([
getPermissionedBurnCheckedInstruction({
account: sourceToken,
mint: mint.address,
permissionedBurnAuthority: burnAuthority,
authority: client.payer,
amount: 1n,
decimals: 0
})
]);

Вычисление размера аккаунта

Вычислите размер mint account для базового mint плюс расширение PermissionedBurnConfig. Этот размер используется в CreateAccount.

Вычисление rent

Вычислите rent, используя размер, необходимый для mint плюс расширение PermissionedBurnConfig.

Создание mint account

Создайте mint account с вычисленными пространством и lamports.

Инициализация PermissionedBurn

Инициализируйте расширение PermissionedBurnConfig на mint с burn authority.

Инициализация mint

Инициализируйте mint с помощью InitializeMint в той же транзакции.

Создать token account и выпустить токены

Создайте token account для плательщика и выпустите на него токены.

Сжечь с использованием полномочий сжигания

Сожгите токены с помощью PermissionedBurnInstruction::BurnChecked, подписанного как владельцем token account, так и органом полномочий сжигания.

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 burnAuthority = await generateKeyPairSigner();
const permissionedBurnExtension = extension("PermissionedBurn", {
authority: burnAuthority.address
});
const mintSpace = BigInt(getMintSize([permissionedBurnExtension]));

Порядок инструкций

PermissionedBurnInstruction::Initialize должна предшествовать InitializeMint. CreateAccount, PermissionedBurnInstruction::Initialize и InitializeMint должны быть включены в одну транзакцию.

Справочник по источникам

ЭлементОписаниеИсточник
PermissionedBurnConfigРасширение минта, хранящее полномочия, необходимые для совместной подписи каждого сжигания для данного минта.Источник
PermissionedBurnInstruction::InitializeИнструкция, инициализирующая конфигурацию разрешённого сжигания перед InitializeMint.Источник
PermissionedBurnInstruction::BurnИнструкция сжигания, требующая подписей от органа полномочий сжигания и владельца token account или его делегата.Источник
PermissionedBurnInstruction::BurnCheckedИнструкция сжигания с проверкой десятичных знаков, использующая те же аккаунты, что и PermissionedBurnInstruction::Burn.Источник
AuthorityType::PermissionedBurnДискриминатор полномочий, используемый совместно с SetAuthority для смены или отключения полномочий сжигания на минте.Источник
process_initializeЛогика процессора, инициализирующая PermissionedBurnConfig на неинициализированном минте и сохраняющая полномочия сжигания.Источник
process_burnЛогика процессора, отклоняющая стандартные операции сжигания при установленных полномочиях сжигания и проверяющая подпись полномочий.Источник
process_set_authorityЛогика процессора, проверяющая и изменяющая полномочия сжигания при использовании AuthorityType::PermissionedBurn.Источник

TypeScript

Приведённый ниже пример с Kit использует сгенерированные инструкции напрямую. Опубликованный устаревший пакет @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 {
AuthorityType,
extension,
fetchMint,
fetchToken,
findAssociatedTokenPda,
getBurnCheckedInstruction,
getCreateAssociatedTokenInstructionAsync,
getInitializeMintInstruction,
getInitializePermissionedBurnInstruction,
getMintSize,
getMintToCheckedInstruction,
getPermissionedBurnCheckedInstruction,
getSetAuthorityInstruction,
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 burnAuthority = await generateKeyPairSigner();
const permissionedBurnExtension = extension("PermissionedBurn", {
authority: burnAuthority.address
});
const mintSpace = BigInt(getMintSize([permissionedBurnExtension]));
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 PermissionedBurnConfig.
programAddress: TOKEN_2022_PROGRAM_ADDRESS // Program that owns the mint account.
}),
getInitializePermissionedBurnInstruction({
mint: mint.address, // Mint account that stores the PermissionedBurnConfig extension.
authority: burnAuthority.address // Authority required to co-sign every burn 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: 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 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: 2n, // Token amount in base units.
decimals: 0 // Decimals defined on the mint.
})
]);
let standardBurnFailure: string | undefined;
try {
await client.sendTransaction([
getBurnCheckedInstruction({
account: sourceToken, // Token account to burn from.
mint: mint.address, // Mint with the permissioned burn configuration.
authority: client.payer, // Token account owner signing the burn.
amount: 1n, // Token amount in base units.
decimals: 0 // Decimals defined on the mint.
})
]);
} catch (error) {
standardBurnFailure = error instanceof Error ? error.message : String(error);
}
if (!standardBurnFailure) {
throw new Error("Expected the standard burn to fail");
}
await client.sendTransaction([
getPermissionedBurnCheckedInstruction({
account: sourceToken, // Token account to burn from.
mint: mint.address, // Mint with the permissioned burn configuration.
permissionedBurnAuthority: burnAuthority, // Burn authority co-signing the burn.
authority: client.payer, // Token account owner signing the burn.
amount: 1n, // Token amount in base units.
decimals: 0 // Decimals defined on the mint.
})
]);
await client.sendTransaction([
getSetAuthorityInstruction({
owned: mint.address, // Mint with the permissioned burn configuration.
owner: burnAuthority, // Current burn authority signing the update.
authorityType: AuthorityType.PermissionedBurn, // Authority type to update.
newAuthority: null // Setting the authority to None disables permissioned burning.
})
]);
await client.sendTransaction([
getBurnCheckedInstruction({
account: sourceToken, // Token account to burn from.
mint: mint.address, // Mint with permissioned burning disabled.
authority: client.payer, // Token account owner signing the burn.
amount: 1n, // Token amount in base units.
decimals: 0 // Decimals defined on the mint.
})
]);
const sourceAccount = await fetchToken(client.rpc, sourceToken);
const mintAccount = await fetchMint(client.rpc, mint.address);
const permissionedBurnConfig = (
unwrapOption(mintAccount.data.extensions) ?? []
).find((item) => isExtension("PermissionedBurn", item));
console.log("Mint Address:", mint.address);
console.log("Error From Failed Standard Burn:", standardBurnFailure);
console.log("Source Amount After Burns:", sourceAccount.data.amount);
console.log("Extension After Disable:", permissionedBurnConfig);

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::{
permissioned_burn::{instruction as permissioned_burn_ix, PermissionedBurnConfig},
BaseStateWithExtensions, ExtensionType, StateWithExtensions,
},
instruction::{burn_checked, initialize_mint, mint_to_checked, set_authority, AuthorityType},
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 burn_authority = 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::PermissionedBurn])?;
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 PermissionedBurnConfig.
&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.
),
permissioned_burn_ix::initialize(
&TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
&mint.pubkey(), // Mint account that stores the PermissionedBurnConfig extension.
&burn_authority.pubkey(), // Authority required to co-sign every burn for 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 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 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.
2, // 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_account_transaction)
.await?;
let standard_burn_ix = burn_checked(
&TOKEN_2022_PROGRAM_ID, // Token program that processes the burn.
&source_token, // Token account to burn from.
&mint.pubkey(), // Mint with the permissioned burn configuration.
&fee_payer.pubkey(), // Token account owner signing the burn.
&[&fee_payer.pubkey()], // Additional multisig signers.
1, // Token amount in base units.
0, // Decimals defined on the mint.
)?;
let standard_burn_transaction = Transaction::new_signed_with_payer(
&[standard_burn_ix],
Some(&fee_payer.pubkey()),
&[&fee_payer],
client.get_latest_blockhash().await?,
);
let standard_burn_result = client
.simulate_transaction(&standard_burn_transaction)
.await?;
let standard_burn_failure = standard_burn_result
.value
.err
.ok_or_else(|| anyhow!("Expected the standard burn to fail"))?;
let permissioned_burn_instruction = permissioned_burn_ix::burn_checked(
&TOKEN_2022_PROGRAM_ID, // Token program that processes the burn.
&source_token, // Token account to burn from.
&mint.pubkey(), // Mint with the permissioned burn configuration.
&burn_authority.pubkey(), // Burn authority co-signing the burn.
&fee_payer.pubkey(), // Token account owner signing the burn.
&[], // Additional multisig signers.
1, // Token amount in base units.
0, // Decimals defined on the mint.
)?;
let permissioned_burn_transaction = Transaction::new_signed_with_payer(
&[permissioned_burn_instruction],
Some(&fee_payer.pubkey()),
&[&fee_payer, &burn_authority],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&permissioned_burn_transaction)
.await?;
let disable_authority_transaction = Transaction::new_signed_with_payer(
&[
set_authority(
&TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
&mint.pubkey(), // Mint with the permissioned burn configuration.
None, // Setting the authority to None disables permissioned burning.
AuthorityType::PermissionedBurn, // Authority type to update.
&burn_authority.pubkey(), // Current burn authority signing the update.
&[], // Additional multisig signers.
)?,
],
Some(&fee_payer.pubkey()),
&[&fee_payer, &burn_authority],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&disable_authority_transaction)
.await?;
let standard_burn_after_disable_transaction = Transaction::new_signed_with_payer(
&[
burn_checked(
&TOKEN_2022_PROGRAM_ID, // Token program that processes the burn.
&source_token, // Token account to burn from.
&mint.pubkey(), // Mint with permissioned burning disabled.
&fee_payer.pubkey(), // Token account owner signing the burn.
&[&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(&standard_burn_after_disable_transaction)
.await?;
let source_account = client.get_account(&source_token).await?;
let source_state = StateWithExtensions::<Account>::unpack(&source_account.data)?;
let mint_account = client.get_account(&mint.pubkey()).await?;
let mint_state = StateWithExtensions::<Mint>::unpack(&mint_account.data)?;
let permissioned_burn_config = mint_state.get_extension::<PermissionedBurnConfig>()?;
println!("Mint Address: {}", mint.pubkey());
println!(
"Error From Failed Standard Burn: {:?}",
standard_burn_failure
);
println!(
"Source Amount After Burns: {}",
u64::from(source_state.base.amount)
);
println!("Extension After Disable: {:?}", permissioned_burn_config);
Ok(())
}

Is this page helpful?

Содержание

Редактировать страницу