spl_token_wrap/mint_customizer/
compliance.rs

1use {
2    crate::mint_customizer::interface::MintCustomizer,
3    solana_account_info::AccountInfo,
4    solana_cpi::invoke,
5    solana_program_error::{ProgramError, ProgramResult},
6    solana_pubkey::Pubkey,
7    solana_zk_sdk::encryption::pod::elgamal::PodElGamalPubkey,
8    spl_token_2022::{
9        extension::{
10            confidential_transfer::instruction::initialize_mint as initialize_confidential_transfer_mint,
11            default_account_state::instruction::initialize_default_account_state,
12            pausable::instruction::initialize as initialize_pausable, ExtensionType,
13            PodStateWithExtensions,
14        },
15        instruction::initialize_permanent_delegate,
16        pod::PodMint,
17        state::{AccountState, Mint},
18    },
19    std::str::FromStr,
20};
21
22/// A reference implementation for a mint `customizer` that adds the following
23/// extensions for compliance-focused use cases:
24/// - A permanent delegate
25/// - `Pausable` transfers, mints, burns
26/// - Confidential transfers with a designated auditor
27///
28/// In the future, can support sRFC-37: https://github.com/solana-foundation/SRFCs/discussions/2
29pub struct ComplianceMintCustomizer;
30
31/// Permanent delegate that can transfer/burn from any account of this mint
32pub const PERMANENT_DELEGATE: Pubkey =
33    solana_pubkey::pubkey!("deLpBmD7UP27BHTuhnxR7mBE9rEV6mWUnwWsXMXTFwR");
34
35/// Authority that manages Confidential Transfer mint settings
36pub const CONFIDENTIAL_TRANSFER_AUTHORITY: Pubkey =
37    solana_pubkey::pubkey!("con2YXp7bKscyhzJzbSQgwz6RFcXqe6otUGK5Rr8saK");
38
39/// Auditor public key for Confidential Transfer amount visibility
40pub const AUDITOR_ELGAMAL_PUBKEY_B64: &str = "yonKhqkoXNvMbN/tU6fjHFhfZuNPpvMj8L55aP2bBG4=";
41
42/// Mint freeze authority enabling freezable tokens
43pub const FREEZE_AUTHORITY: Pubkey =
44    solana_pubkey::pubkey!("freTRAXwCVELv5k7V6UobnCiG1hmhnj79AezxRwAR3h");
45
46/// Mint pause authority enabling `pausable` tokens
47pub const PAUSE_AUTHORITY: Pubkey =
48    solana_pubkey::pubkey!("pauySfjziLCpPMoaeFsWgvBCe7ygHKr6wXCyvTNZyGv");
49
50impl MintCustomizer for ComplianceMintCustomizer {
51    fn get_token_2022_mint_space() -> Result<usize, ProgramError> {
52        ExtensionType::try_calculate_account_len::<Mint>(&[
53            ExtensionType::PermanentDelegate,
54            ExtensionType::DefaultAccountState,
55            ExtensionType::ConfidentialTransferMint,
56            ExtensionType::Pausable,
57        ])
58    }
59
60    fn initialize_extensions(
61        wrapped_mint_account: &AccountInfo,
62        wrapped_token_program_account: &AccountInfo,
63    ) -> ProgramResult {
64        // This delegate can burn or transfer tokens from any account for this mint,
65        // even without an explicit approval
66        invoke(
67            &initialize_permanent_delegate(
68                wrapped_token_program_account.key,
69                wrapped_mint_account.key,
70                &PERMANENT_DELEGATE,
71            )?,
72            &[wrapped_mint_account.clone()],
73        )?;
74
75        // Enables private transactions and specifies an auditor that can decrypt
76        // transaction amounts for compliance
77        let elgamal_pubkey = PodElGamalPubkey::from_str(AUDITOR_ELGAMAL_PUBKEY_B64)
78            .map_err(|_| ProgramError::InvalidArgument)?;
79        invoke(
80            &initialize_confidential_transfer_mint(
81                wrapped_token_program_account.key,
82                wrapped_mint_account.key,
83                Some(CONFIDENTIAL_TRANSFER_AUTHORITY), // Authority to manage settings
84                true,
85                // Enable compliance monitoring by allowing auditor to decrypt confidential
86                // transfer amounts
87                Some(elgamal_pubkey),
88            )?,
89            &[wrapped_mint_account.clone()],
90        )?;
91
92        // By default, new accounts are initialized. The freeze authority can freeze
93        // them individually.
94        invoke(
95            &initialize_default_account_state(
96                wrapped_token_program_account.key,
97                wrapped_mint_account.key,
98                &AccountState::Initialized,
99            )?,
100            &[wrapped_mint_account.clone()],
101        )?;
102
103        // The pause authority can pause transfers, burns, and mints
104        invoke(
105            &initialize_pausable(
106                wrapped_token_program_account.key,
107                wrapped_mint_account.key,
108                &PAUSE_AUTHORITY,
109            )?,
110            &[wrapped_mint_account.clone()],
111        )?;
112
113        Ok(())
114    }
115
116    fn get_freeze_auth_and_decimals(
117        unwrapped_mint_account: &AccountInfo,
118    ) -> Result<(Option<Pubkey>, u8), ProgramError> {
119        // Copy decimals from the original unwrapped mint.
120        let unwrapped_mint_data = unwrapped_mint_account.try_borrow_data()?;
121        let pod_mint = PodStateWithExtensions::<PodMint>::unpack(&unwrapped_mint_data)?.base;
122        let decimals = pod_mint.decimals;
123
124        // By setting a freeze authority, we enable "pausable" functionality. The freeze
125        // authority can freeze all token accounts, effectively pausing transfers.
126        Ok((Some(FREEZE_AUTHORITY), decimals))
127    }
128}