5 solana token transfer to pool

我想要将solana的任何spl token能够通过inbox转移到当前程序账户下,然后任何token都能通过outbox从当前程序账户下转移到用户,我的代码好像是有误的,希望老师们能帮忙解决下,solana小白。

use anchor_lang::prelude::*;
use anchor_lang::solana_program::system_instruction;
use anchor_spl::token::{self, Token, TokenAccount, Transfer};

#[account]
pub struct MappingMakerToBool {
    pub mappings: Vec<PubkeyBoolPair>,
}
impl MappingMakerToBool {
    pub fn set(&mut self, key: Pubkey, value: bool) {
        if let Some(pair) = self.mappings.iter_mut().find(|pair| pair.key == key) {
            pair.value = value;
        } else {
            self.mappings.push(PubkeyBoolPair { key, value });
        }
    }

    pub fn get(&self, key: Pubkey) -> Option<bool> {
        self.mappings
            .iter()
            .find(|pair| pair.key == key)
            .map(|pair| pair.value)
    }
}

#[program]
mod test {
 //初始化
    pub fn initialize(
        ctx: Context<Initialize>,
        owner: Pubkey,
        fee: u64,
        fee_receiver: Pubkey,
        paused: bool,
    ) -> Result<()> {
        let init_state = &mut ctx.accounts.state;
        // require!(
        //     ctx.accounts.user.key().to_string() == INIT_OPERATOR,
        //     ErrorCode::NoPermission
        // );
        // 确保只能调用一次
        require!(!init_state.initialized, ErrorCode::AlreadyInitialized);

        let (pda, bump) = Pubkey::find_program_address(
            &[b"authority", init_state.key().as_ref()],
            ctx.program_id,
        );
        // PDA seeds and bump to "sign" for CPI
        // let seeds = b"authority";
        // let bump = ctx.bumps.reward_token_mint;
        // let signer: &[&[&[u8]]] = &[&[seeds, &[bump]]];

        require!(fee <= 10000, ErrorCode::FeeOver10000);
        init_state.bump = bump;
        init_state.program_pda = pda;

        init_state.owner = owner;
        init_state.fee = fee;
        init_state.fee_receiver = fee_receiver;

        init_state.paused = paused;
        init_state.initialized = true; 
        Ok(())
    }

 pub fn set_maker_list(
        ctx: Context<SetMakerList>,
        makers: Vec<Pubkey>,
        status: Vec<bool>,
    ) -> Result<()> {
        let state = &mut ctx.accounts.state;
        require!(
            state.owner == ctx.accounts.user.key(),
            ErrorCode::NoPermission
        );
        require!(makers.len() == status.len(), ErrorCode::InvalidLength);
        let maker_valid = &mut ctx.accounts.maker_valid;
        for (i, &maker) in makers.iter().enumerate() {
            maker_valid.set(maker, status[i]);
        }
        emit!(ChangeMakers {
            state_key: state.key(),
            new_makers: makers,
        });
        Ok(())
    }

pub fn inbox(ctx: Context<Inbox>, amount: u64, data: Vec<u8>) -> Result<()> {
        let state = &ctx.accounts.state;
        require!(!state.paused, ErrorCode::ContractPaused);
        let maker_valid = &mut ctx.accounts.maker_valid;
        let if_maker_valid = maker_valid.get(ctx.accounts.user.key()).unwrap_or(false);
        require!(if_maker_valid, ErrorCode::NotMaker);
        let required_fee = state.fee;
        let fee_amount = amount
            .checked_mul(required_fee)
            .and_then(|v| v.checked_div(10000))
            .ok_or(ErrorCode::InsufficientAmount)?;
        let real_in_amount = amount.checked_sub(fee_amount).ok_or(ErrorCode::Overflow)?;

        require!(fee_amount <= real_in_amount, ErrorCode::InvalidFeeAmount);
        //Transfer fee to feeReceiver

        if fee_amount > 0 {
            // Transfer fee to feeReceiver
            let cpi_accounts = Transfer {
                from: ctx.accounts.source.to_account_info(),
                to: ctx.accounts.fee_destination.to_account_info(),
                authority: ctx.accounts.user.to_account_info(),
            };
            let cpi_program = ctx.accounts.token_program.to_account_info();
            let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
            token::transfer(cpi_ctx, fee_amount)?;

            emit!(InboxFeeEvent {
                token: ctx.accounts.contract_token_account.key(),
                sender: ctx.accounts.user.key(),
                fee_receiver: state.fee_receiver.key(),
                fee_amount: fee_amount,
            });
        }

        // Transfer tokens inbox(state)
        let cpi_accounts = Transfer {
            from: ctx.accounts.contract_token_account.to_account_info(),
            to: ctx.accounts.destination.to_account_info(),
            authority: ctx.accounts.user.to_account_info(),
        };
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
        token::transfer(cpi_ctx, real_in_amount)?;

        emit!(InboxEvent {
            token: ctx.accounts.contract_token_account.key(),
            sender: ctx.accounts.user.key(),
            receiver: ctx.accounts.destination.key(),
            amount: real_in_amount,
            data: data,
        });
        Ok(())
    }

    pub fn outbox(ctx: Context<Outbox>, amount: u64, data: Vec<u8>) -> Result<()> {
        let state = &ctx.accounts.state;
        require!(!state.paused, ErrorCode::ContractPaused);
        let maker_valid = &mut ctx.accounts.maker_valid;
        let if_maker_valid = maker_valid.get(ctx.accounts.user.key()).unwrap_or(false);
        require!(if_maker_valid, ErrorCode::NotMaker);

        //Token Transfer
        // let seeds = &[&[state.bump]];
        // let signer_seeds = &[&seeds[..]];

        // let seeds = b"authority";
        // let bump = state.bump;
        // let signer: &[&[&[u8]]] = &[&[seeds, &[bump]]];

        let state_key = state.key();
        let seeds = &[b"authority", state_key.as_ref(), &[state.bump]];
        let signer_seeds = &[&seeds[..]];

        let cpi_accounts = Transfer {
            from: ctx.accounts.source.to_account_info(),
            to: ctx.accounts.destination.to_account_info(),
            authority: ctx.accounts.contract_authority.to_account_info(),
        };
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_ctx = CpiContext::new_with_signer(cpi_program, cpi_accounts, signer_seeds);
        token::transfer(cpi_ctx, amount)?;

        emit!(OutboxEvent {
            token: ctx.accounts.contract_token_account.key(),
            sender: ctx.accounts.source.key(),
            receiver: ctx.accounts.destination.key(),
            amount: amount,
            data: data,
        });
        Ok(())
    }

}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = user, space = 8 + 256)]
    pub state: Account<'info, InitializeState>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct SetMakerList<'info> {
    pub state: Account<'info, InitializeState>,
    #[account(init, payer = user, space = 8 + 1024)]
    pub maker_valid: Account<'info, MappingMakerToBool>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Inbox<'info> {
    pub state: Account<'info, InitializeState>,
    #[account(mut)]
    pub user: Signer<'info>,
    #[account(mut)]
    pub source: Account<'info, TokenAccount>,
    #[account(mut)]
    pub destination: Account<'info, TokenAccount>,
    #[account(mut)]
    pub fee_destination: Account<'info, TokenAccount>,
    #[account(mut)]
    pub contract_token_account: Account<'info, TokenAccount>,
    pub token_program: Program<'info, Token>,
    pub system_program: Program<'info, System>,
    pub maker_valid: Account<'info, MappingMakerToBool>,
}

#[derive(Accounts)]
pub struct Outbox<'info> {
    pub state: Account<'info, InitializeState>,
    #[account(mut)]
    pub user: Signer<'info>,
    #[account(mut)]
    pub contract_token_account: Account<'info, TokenAccount>,
    #[account(mut)]
    pub source: Account<'info, TokenAccount>,
    #[account(mut)]
    pub destination: Account<'info, TokenAccount>,
    #[account(seeds = [b"authority", state.key().as_ref()],bump = state.bump)]
    pub contract_authority: AccountInfo<'info>,
    pub token_program: Program<'info, Token>,
    pub maker_valid: Account<'info, MappingMakerToBool>,
}

#[account]
pub struct InitializeState {
    pub bump: u8,
    pub program_pda: Pubkey,
    pub owner: Pubkey,
    pub paused: bool,
    pub fee: u64,
    pub fee_receiver: Pubkey,
    pub initialized: bool,
}

#[error_code]
pub enum ErrorCode {
    #[msg("No permission to perform this action.")]
    NoPermission,
    #[msg("Initialization has been performed.")]
    AlreadyInitialized,
    #[msg("Insufficient amount.")]
    InsufficientAmount,
    #[msg("Contract is paused.")]
    ContractPaused,
    #[msg("Invalid length.")]
    InvalidLength,
    #[msg("Invalid fee amount")]
    InvalidFeeAmount,
    #[msg("Overflow")]
    Overflow,
    #[msg("Not a maker.")]
    NotMaker,
    #[msg("Fee over 10000.")]
    FeeOver10000,
    #[msg("Not a manager")]
    NotManager,
}

#[event]
pub struct OwnerChangeEvent {
    pub old_owner: Pubkey,
    pub new_owner: Pubkey,
}

#[event]
pub struct ChangeMakers {
    pub state_key: Pubkey,
    pub new_makers: Vec<Pubkey>,
}

#[event]
pub struct InboxEvent {
    pub token: Pubkey,
    pub sender: Pubkey,
    pub receiver: Pubkey,
    pub amount: u64,
    pub data: Vec<u8>,
}

#[event]
pub struct InboxFeeEvent {
    pub token: Pubkey,
    pub sender: Pubkey,
    pub fee_receiver: Pubkey,
    pub fee_amount: u64,
}

#[event]
pub struct OutboxEvent {
    pub token: Pubkey,
    pub sender: Pubkey,
    pub receiver: Pubkey,
    pub amount: u64,
    pub data: Vec<u8>,
}
请先 登录 后评论
  • 0 关注
  • 0 收藏,809 浏览
  • ? or ? 提出于 2024-07-24 15:04