defios 0.1.0

Main github on-chain integrations by DefiOS
Documentation
use anchor_lang::prelude::*;
use anchor_spl::{
    associated_token::get_associated_token_address,
    token::{transfer, Mint, Token, TokenAccount, Transfer},
};

use crate::{
    error::DefiOSError,
    state::{Repository, VestingSchedule},
};

#[derive(Accounts)]
pub struct UnlockTokens<'info> {
    #[account(
        mut,
        address = repository_account.repository_creator.key() @ DefiOSError::UnauthorizedUser,
    )]
    pub repository_creator: Signer<'info>,

    #[account(
        mut,
        constraint = repository_creator_token_account.mint.eq(&token_mint.key()),
        address = vesting_account.destination_address,
    )]
    pub repository_creator_token_account: Account<'info, TokenAccount>,

    #[account(
        address = vesting_account.mint_address,
    )]
    pub token_mint: Account<'info, Mint>,

    #[account(
        seeds = [
            b"repository",
            repository_account.id.as_bytes(),
            repository_creator.key().as_ref(),
        ],
        bump=repository_account.bump
    )]
    pub repository_account: Account<'info, Repository>,

    #[account(
        mut,
        seeds = [
            b"vesting",
            repository_account.key().as_ref(),
        ],
        constraint = vesting_account.mint_address == repository_account.repo_token,
        bump = vesting_account.bump
    )]
    pub vesting_account: Account<'info, VestingSchedule>,

    #[account(
        mut,
        constraint = vesting_token_account.mint.eq(&token_mint.key()),
        constraint = vesting_token_account.owner.eq(&vesting_account.key())
    )]
    pub vesting_token_account: Account<'info, TokenAccount>,
    pub system_program: Program<'info, System>,
    pub token_program: Program<'info, Token>,
}

pub fn handler(ctx: Context<UnlockTokens>) -> Result<()> {
    let vesting_account = &mut ctx.accounts.vesting_account;
    let repository_creator = &mut ctx.accounts.repository_creator;
    let repository_account = &ctx.accounts.repository_account;
    let token_program = &ctx.accounts.token_program;
    let repository_creator_token_account = &ctx.accounts.repository_creator_token_account;
    let vesting_token_account = &ctx.accounts.vesting_token_account;
    let rewards_mint = &ctx.accounts.token_mint;
    let current_timestamp = Clock::get()?.unix_timestamp;

    let expected_repository_creator_token_account =
        get_associated_token_address(&repository_creator.key(), &rewards_mint.key());

    require!(
        expected_repository_creator_token_account.eq(&repository_creator_token_account.key()),
        DefiOSError::TokenAccountMismatch
    );

    let mut total_transfer_tokens = 0;
    for s in vesting_account.schedules.iter_mut() {
        if current_timestamp as u64 >= s.release_time {
            total_transfer_tokens += s.amount;
            s.amount = 0;
        }
    }

    require!(
        total_transfer_tokens > 0,
        DefiOSError::VestingNotReachedRelease
    );

    let repository_account_key = repository_account.key();
    let signer_seeds: &[&[&[u8]]] = &[&[
        b"vesting",
        repository_account_key.as_ref(),
        &[vesting_account.bump],
    ]];

    transfer(
        CpiContext::new_with_signer(
            token_program.to_account_info(),
            Transfer {
                from: vesting_token_account.to_account_info(),
                to: repository_creator_token_account.to_account_info(),
                authority: vesting_account.to_account_info(),
            },
            signer_seeds,
        ),
        total_transfer_tokens,
    )?;

    Ok(())
}