light_token/instruction/
mint_to.rs

1use light_sdk_types::LIGHT_TOKEN_PROGRAM_ID;
2use solana_account_info::AccountInfo;
3use solana_cpi::{invoke, invoke_signed};
4use solana_instruction::{AccountMeta, Instruction};
5use solana_program_error::ProgramError;
6use solana_pubkey::Pubkey;
7
8/// # Mint tokens to a ctoken account (simple 3-account instruction):
9/// ```rust
10/// # use solana_pubkey::Pubkey;
11/// # use light_token::instruction::MintTo;
12/// # let mint = Pubkey::new_unique();
13/// # let destination = Pubkey::new_unique();
14/// # let authority = Pubkey::new_unique();
15/// let instruction = MintTo {
16///     mint,
17///     destination,
18///     amount: 100,
19///     authority,
20///     max_top_up: None,
21/// }.instruction()?;
22/// # Ok::<(), solana_program_error::ProgramError>(())
23/// ```
24pub struct MintTo {
25    /// Mint account (supply tracking)
26    pub mint: Pubkey,
27    /// Destination Light Token account to mint to
28    pub destination: Pubkey,
29    /// Amount of tokens to mint
30    pub amount: u64,
31    /// Mint authority
32    pub authority: Pubkey,
33    /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit)
34    /// When set to a non-zero value, includes max_top_up in instruction data
35    pub max_top_up: Option<u16>,
36}
37
38/// # Mint to ctoken via CPI:
39/// ```rust,no_run
40/// # use light_token::instruction::MintToCpi;
41/// # use solana_account_info::AccountInfo;
42/// # let mint: AccountInfo = todo!();
43/// # let destination: AccountInfo = todo!();
44/// # let authority: AccountInfo = todo!();
45/// # let system_program: AccountInfo = todo!();
46/// MintToCpi {
47///     mint,
48///     destination,
49///     amount: 100,
50///     authority,
51///     system_program,
52///     max_top_up: None,
53/// }
54/// .invoke()?;
55/// # Ok::<(), solana_program_error::ProgramError>(())
56/// ```
57pub struct MintToCpi<'info> {
58    pub mint: AccountInfo<'info>,
59    pub destination: AccountInfo<'info>,
60    pub amount: u64,
61    pub authority: AccountInfo<'info>,
62    pub system_program: AccountInfo<'info>,
63    /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit)
64    pub max_top_up: Option<u16>,
65}
66
67impl<'info> MintToCpi<'info> {
68    pub fn instruction(&self) -> Result<Instruction, ProgramError> {
69        MintTo::from(self).instruction()
70    }
71
72    pub fn invoke(self) -> Result<(), ProgramError> {
73        let instruction = MintTo::from(&self).instruction()?;
74        let account_infos = [
75            self.mint,
76            self.destination,
77            self.authority,
78            self.system_program,
79        ];
80        invoke(&instruction, &account_infos)
81    }
82
83    pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
84        let instruction = MintTo::from(&self).instruction()?;
85        let account_infos = [
86            self.mint,
87            self.destination,
88            self.authority,
89            self.system_program,
90        ];
91        invoke_signed(&instruction, &account_infos, signer_seeds)
92    }
93}
94
95impl<'info> From<&MintToCpi<'info>> for MintTo {
96    fn from(cpi: &MintToCpi<'info>) -> Self {
97        Self {
98            mint: *cpi.mint.key,
99            destination: *cpi.destination.key,
100            amount: cpi.amount,
101            authority: *cpi.authority.key,
102            max_top_up: cpi.max_top_up,
103        }
104    }
105}
106
107impl MintTo {
108    pub fn instruction(self) -> Result<Instruction, ProgramError> {
109        Ok(Instruction {
110            program_id: Pubkey::from(LIGHT_TOKEN_PROGRAM_ID),
111            accounts: vec![
112                AccountMeta::new(self.mint, false),
113                AccountMeta::new(self.destination, false),
114                AccountMeta::new(self.authority, true),
115                AccountMeta::new_readonly(Pubkey::default(), false), // System program for lamport transfers
116            ],
117            data: {
118                let mut data = vec![7u8]; // MintTo discriminator
119                data.extend_from_slice(&self.amount.to_le_bytes());
120                // Include max_top_up if set (10-byte format)
121                if let Some(max_top_up) = self.max_top_up {
122                    data.extend_from_slice(&max_top_up.to_le_bytes());
123                }
124                data
125            },
126        })
127    }
128}