1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
| use std::collections::HashMap; use anchor_lang::prelude::*; use anchor_spl::{ associated_token::get_associated_token_address, token::{mint_to, spl_token, MintTo}, token_2022::{self, spl_token_2022::{extension::StateWithExtensions, state::Mint as Mint2022}}, };
pub fn etf_token_mint<'info>( ctx: Context<'_, '_, '_, 'info, EtfTokenTransaction<'info>>, lamports: f64, ) -> Result<()> { let m = ctx.accounts.etf_token_mint_account.key(); let signer_seeds: &[&[&[u8]]] = &[&[ EtfToken::SEED_PREFIX.as_bytes(), m.as_ref(), &[ctx.bumps.etf_token_info], ]];
let accounts = ctx .remaining_accounts .iter() .map(|x| (x.key(), x.to_owned())) .collect::<HashMap<_, _>>();
for x in &ctx.accounts.etf_token_info.assets { let from_ata = accounts .get(&get_associated_token_address( &ctx.accounts.authority.key(), &x.token, )) .ok_or(TokenMintError::InvalidAccounts)?;
let to_ata = accounts .get(&get_associated_token_address( &ctx.accounts.etf_token_info.key(), &x.token, )) .ok_or(TokenMintError::InvalidAccounts)?;
let mint_account = accounts .get(&x.token) .ok_or(TokenMintError::InvalidAccounts)?; let mint_data = mint_account.try_borrow_data()?;
let (decimals, token_program_id) = if *mint_account.owner == token_2022::ID { let mint_state = StateWithExtensions::<Mint2022>::unpack(&mint_data)?; (mint_state.base.decimals, token_2022::ID) } else { let mint_state = spl_token::state::Mint::unpack(&mint_data)?; (mint_state.decimals, anchor_spl::token::ID) };
let weight = x.weight as f64; let base = 10u64.pow(decimals as u32); let lamports_in_smallest_unit = (lamports * base as f64).round(); let amount = ((weight * lamports_in_smallest_unit) / 100.0).round() as u64;
let token_program = ctx .remaining_accounts .iter() .find(|account| account.key == &token_program_id) .ok_or(TokenMintError::InvalidAccounts)?;
transfer_tokens( ctx.accounts.authority.to_account_info(), from_ata.to_account_info(), to_ata.to_account_info(), mint_account.clone(), token_program.to_account_info(), amount, decimals, Some(signer_seeds), )?;
msg!("success transfer token: {} {}", x.token, amount / base); }
let mint_amount = (lamports * (10u64.pow(EtfToken::TOKEN_DECIMALS as u32) as f64)) as u64; mint_to( CpiContext::new_with_signer( ctx.accounts.token_program.to_account_info(), MintTo { mint: ctx.accounts.etf_token_mint_account.to_account_info(), to: ctx.accounts.etf_token_ata.to_account_info(), authority: ctx.accounts.etf_token_info.to_account_info(), }, signer_seeds, ), mint_amount, )?;
msg!("token minted successfully. {} {}", ctx.accounts.etf_token_mint_account.key(), lamports);
emit!(EtfTokenMintEvent { etf_token_mint: ctx.accounts.etf_token_mint_account.key(), authority: ctx.accounts.authority.key(), lamports, });
Ok(()) }
|