Руководство эмитента по конфиденциальным балансам

Выпуск токенов с конфиденциальными балансами на Solana

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

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

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

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

  • Политика подтверждения: могут ли аккаунты подключаться к конфиденциальным балансам без разрешений (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?