Руководство эмитента по Confidential Transfer

Выпуск токенов Confidential Transfer на Solana

Это руководство предназначено для эмитентов — команд, создающих и обслуживающих минт Token-2022 с расширением Confidential Transfer. В нём рассматриваются решения, принимаемые при создании минта, и операции, выполняемые на протяжении всего жизненного цикла минта. Информацию о действиях со стороны держателя (депозит, применение, перевод, вывод) см. в пошаговых инструкциях, а о поддержке этих токенов в продукте — в Руководстве по интеграции.

Конфиденциальные переводы сохраняют суммы переводов и балансы аккаунтов зашифрованными, оставляя адреса аккаунтов, минт и владельцев общедоступными. Они опираются на программу ZK ElGamal Proof Program для верификации доказательств в блокчейне, поэтому минт доступен только в кластерах, где эта программа включена.

Решения, принимаемые при создании

Расширение Confidential Transfer должно быть инициализировано до инициализации минта и не может быть добавлено позже. При создании вы определяете:

  • Политика подтверждения: могут ли аккаунты подключаться к конфиденциальным переводам без разрешения (auto) или должны быть одобрены органом конфиденциальных переводов минта (manual).
  • Аудитор: устанавливать ли глобальный публичный ключ ElGamal аудитора, чтобы назначенная сторона могла расшифровывать каждую сумму перевода для минта. Необязательно, может быть изменено позже.
  • Опциональные дополнительные расширения: конфиденциальные комиссии за перевод (в паре с расширением для комиссий) и конфиденциальный минт/сжигание — оба рассматриваются ниже. Они также должны быть инициализированы при создании.

Создание конфиденциального минта

CLI устанавливает политику подтверждения с помощью --enable-confidential-transfers auto или manual; auto позволяет любому держателю настроить собственный аккаунт, тогда как manual требует одобрения от органа конфиденциальных переводов (по умолчанию — орган минта). Клиентские пути принимают те же настройки через параметры ConfidentialTransferMint: орган, флаг автоматического подтверждения и необязательный ключ аудитора. Как политику подтверждения, так и аудитора можно изменить позже (см. Настройка аудитора); фиксированным при создании остаётся только само наличие расширения.

$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-confidential-transfers auto

Настройка аудитора

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

Полномочный орган по конфиденциальным переводам может устанавливать, заменять или удалять аудитора в любое время. Та же операция также обновляет политику подтверждения. В CLI ключ аудитора представляет собой base64-кодировку публичного ключа ElGamal; передайте --auditor-pubkey none, чтобы удалить его, и --approve-policy auto|manual, чтобы изменить политику.

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

$ spl-token update-confidential-transfer-settings <MINT_PUBKEY> --auditor-pubkey <AUDITOR_ELGAMAL_PUBKEY>

Секретный ключ аудитора позволяет расшифровать каждую сумму перевода для данного минта. Храните его с той же степенью защиты, что и ключ подписи, и планируйте его замену. Установка аудитора в значение None отключает видимость сумм для всех, кроме самих владельцев аккаунтов.

Подтверждение аккаунтов (ручная политика)

При ручной политике подтверждения аккаунт, настроенный для конфиденциальных переводов, не может совершать конфиденциальные транзакции до тех пор, пока полномочный орган по конфиденциальным переводам не подтвердит его. Это даёт эмитентам инструмент контроля доступа для участников из списка разрешённых или прошедших KYC-проверку. CLI не предоставляет команды подтверждения, поэтому оно выполняется через клиент.

token
.confidential_transfer_approve_account(
&token_account,
&authority,
&[&authority_keypair],
)
.await?;

Комиссии за конфиденциальные переводы

Если ваш минт взимает комиссию за перевод, а переводы являются конфиденциальными, комиссия также должна удерживаться конфиденциально. Расширение ConfidentialTransferFeeConfig обеспечивает это и инициализируется при создании минта вместе с расширениями комиссии за перевод и конфиденциального перевода.

Удержанные комиссии накапливаются в зашифрованном виде на аккаунтах получателей, затем перемещаются на минт и впоследствии снимаются полномочным органом по выводу удержанных средств. Все суммы комиссий остаются зашифрованными на протяжении всего процесса. Ничего из этого не доступно через CLI. Секретный ключ ElGamal полномочного органа по выводу удержанных средств позволяет расшифровать суммы удержанных комиссий, что в сочетании с публичными параметрами комиссии может раскрыть информацию о суммах переводов — обращайтесь с этим ключом как с конфиденциальными данными.

Инициализация конфигурации комиссий

Включите это вместе с ConfidentialTransferMint и конфигурацией комиссии за перевод при создании минта.

use spl_token_client::token::ExtensionInitializationParams;
ExtensionInitializationParams::ConfidentialTransferFeeConfig {
authority: Some(authority.pubkey().into()),
withdraw_withheld_authority_elgamal_pubkey: withdraw_withheld_elgamal_pubkey,
};

Сбор и вывод удержанных комиссий

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

  • Управляющий комиссией за конфиденциальный перевод (authority, установленный в ConfidentialTransferFeeConfig) включает или отключает сбор.
  • Управляющий выводом удержанных средств (из поля TransferFeeConfig расширения комиссии за перевод) выводит собранные комиссии из минта.

Вывод требует доказательства равенства и диапазона, передаваемых встроенно или верифицированных в аккаунты состояния контекста.

// Permissionless: move withheld fees from accounts into the mint.
token
.confidential_transfer_harvest_withheld_tokens_to_mint(&[&source_account])
.await?;
// Withdraw withheld fees from the mint (requires the withdraw withheld authority).
token
.confidential_transfer_withdraw_withheld_tokens_from_mint(
&destination_account,
&withdraw_withheld_authority,
None, // proof context state account, supplied inline if None
None, // withheld tokens info, fetched if None
&withdraw_withheld_elgamal_keypair,
&destination_elgamal_pubkey,
&new_decryptable_available_balance,
&[&withdraw_withheld_authority_keypair],
)
.await?;

В JS-клиенте вывод собранных комиссий из минта (getWithdrawWithheldTokensFromMintForConfidentialTransferFeeInstruction) дополнительно требует доказательства равенства и диапазона, верифицированных в аккаунты состояния контекста, поэтому он следует той же схеме с аккаунтами доказательств, что и конфиденциальный перевод.

Конфиденциальный минт и сжигание

Расширение ConfidentialMintBurn позволяет управляющему минтом выпускать и сжигать токены непосредственно из конфиденциальных балансов, сохраняя общее предложение зашифрованным. Минт с этим расширением отключает публичный путь внесения и вывода, поскольку токены существуют исключительно в конфиденциальном виде. См. документацию по протоколу для ознакомления с полной моделью.

Конфиденциальный минт/сжигание проще всего выполнять через Rust spl-token-client, который автоматически генерирует необходимые доказательства и выстраивает последовательность транзакций. JS-клиент @solana-program/token-2022 содержит низкоуровневые конструкторы инструкций (getConfidentialMintInstruction, getConfidentialBurnInstruction и другие), но не предоставляет высокоуровневого помощника для построения доказательств, а CLI-команды отсутствуют — поэтому приведённые ниже примеры написаны только на Rust.

Инициализируйте расширение при создании минта, затем выполняйте минтинг, сжигание и сверку супплая со временем. Минтинг выпускает зашифрованную сумму на конфиденциальный баланс получателя; сжигание удаляет зашифрованную сумму в ожидающее сжигание, которое впоследствии включается в супплай. Оба процесса генерируют доказательства, аналогично конфиденциальному переводу.

confidential-mint-burn.rs
use spl_token_client::token::ExtensionInitializationParams;
// 1. Initialize at creation (alongside ConfidentialTransferMint).
ExtensionInitializationParams::ConfidentialMintBurn {
supply_elgamal_pubkey, // encrypts the confidential supply
decryptable_supply, // AES ciphertext of the initial supply (zero)
};
// 2. Mint an encrypted amount into a recipient's confidential balance.
token
.confidential_transfer_mint(
&mint_authority,
&destination_account,
None, // equality proof account
None, // ciphertext validity proof account
None, // range proof account
mint_amount,
&supply_elgamal_keypair,
&destination_elgamal_pubkey,
auditor_elgamal_pubkey, // Option
&supply_aes_key,
None, // supply account info, fetched if None
&[&mint_authority_keypair],
)
.await?;
// 3. Burn an encrypted amount from a holder's confidential balance into the
// mint's pending burn. Generates proofs like a confidential transfer.
token
.confidential_transfer_burn(
&owner,
&source_account,
None, // equality proof account
None, // ciphertext validity proof account
None, // range proof account
burn_amount,
&source_elgamal_keypair,
&supply_elgamal_pubkey,
auditor_elgamal_pubkey, // Option
&source_aes_key,
None, // burn account info, fetched if None
&[&owner_keypair],
)
.await?;
// 4. Fold the accumulated pending burn into the confidential supply.
token
.confidential_transfer_apply_pending_burn(&mint_authority, &[&mint_authority_keypair])
.await?;

Смените ключ шифрования супплая с помощью confidential_transfer_rotate_supply_elgamal_pubkey (ожидающее сжигание должно быть сначала равно нулю), и обновите читаемый зашифрованный текст супплая с помощью confidential_transfer_update_decrypt_supply.

Операционные соображения и соответствие требованиям

  • Хранение ключа аудитора. Если вы назначаете аудитора, секретный ключ аудитора является высокоценным ключом дешифрования. Храните и меняйте его с осторожностью, и определите, кто в вашей организации (или какой регулятор) им владеет.
  • Политика соответствия. Проверка адресов и анализ графа контрагентов продолжают работать, поскольку адреса остаются публичными. Мониторинг на основе сумм зависит от ключа аудитора или от избирательного раскрытия информации владельцами аккаунтов. Определите свой подход до запуска.
  • Подключение держателей. Настройка конфиденциального аккаунта требует подписи владельца. Для плавной подготовки аккаунтов для пользователей попросите их однократно зарегистрировать ключ ElGamal и использовать путь через реестр, описанный в Руководстве по интеграции.
  • Количество транзакций. Конфиденциальный перевод в настоящее время охватывает несколько зависимых транзакций, поскольку доказательства превышают текущий лимит размера транзакции. Формат транзакции v1 (появится с Agave v4.2) увеличивает этот лимит и, как ожидается, позволит выполнять одну транзакцию в блокчейне.

Is this page helpful?