use crate::{
error::DefiOSError,
event::RewardClaimed,
state::{Issue, PullRequest, Repository},
};
use anchor_lang::prelude::*;
use anchor_spl::{
associated_token::{
create as create_associated_token_account, get_associated_token_address, AssociatedToken,
Create,
},
token::{transfer, Mint, Token, TokenAccount, Transfer},
};
#[derive(Accounts)]
pub struct ClaimReward<'info> {
#[account(
mut,
constraint = pull_request_creator.key().eq(&pull_request.sent_by) @ DefiOSError::UnauthorizedUser,
)]
pub pull_request_creator: Signer<'info>,
#[account(
mut,
seeds = [
b"pullrequestadded",
issue_account.key().as_ref(),
pull_request_creator.key().as_ref()
],
bump = pull_request.bump
)]
pub pull_request: Account<'info, PullRequest>,
#[account(mut)]
pub pull_request_creator_reward_account: UncheckedAccount<'info>,
#[account(
constraint = rewards_mint.key() == issue_account.issue_token,
constraint = rewards_mint.key() == issue_token_pool_account.mint
)]
pub rewards_mint: Account<'info, Mint>,
#[account(
address = repository_account.repository_creator
)]
pub repository_creator: SystemAccount<'info>,
#[account(
address = issue_account.issue_creator
)]
pub issue_creator: SystemAccount<'info>,
#[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"issue",
issue_account.index.to_string().as_bytes(),
repository_account.key().as_ref(),
issue_creator.key().as_ref(),
],
bump = issue_account.bump
)]
pub issue_account: Box<Account<'info, Issue>>,
#[account(
mut,
constraint = issue_token_pool_account.owner == issue_account.key()
)]
pub issue_token_pool_account: Box<Account<'info, TokenAccount>>,
pub system_program: Program<'info, System>,
pub associated_token_program: Program<'info, AssociatedToken>,
pub token_program: Program<'info, Token>,
}
pub fn handler(ctx: Context<ClaimReward>) -> Result<()> {
let pull_request_creator = &mut ctx.accounts.pull_request_creator;
let rewards_mint = &ctx.accounts.rewards_mint;
let repository_account = &ctx.accounts.repository_account;
let issue_account = &mut ctx.accounts.issue_account;
let pull_request_creator_reward_account = &mut ctx.accounts.pull_request_creator_reward_account;
let issue_token_pool_account = &mut ctx.accounts.issue_token_pool_account;
let associated_token_program = &ctx.accounts.associated_token_program;
let system_program = &ctx.accounts.system_program;
let token_program = &ctx.accounts.token_program;
let pull_request = &mut ctx.accounts.pull_request;
if pull_request_creator_reward_account.data_is_empty() {
create_associated_token_account(CpiContext::new(
associated_token_program.to_account_info(),
Create {
payer: pull_request_creator.to_account_info(),
associated_token: pull_request_creator_reward_account.to_account_info(),
authority: pull_request_creator.to_account_info(),
mint: rewards_mint.to_account_info(),
system_program: system_program.to_account_info(),
token_program: token_program.to_account_info(),
},
))?;
}
let expected_pull_request_creator_reward_account =
get_associated_token_address(&pull_request_creator.key(), &rewards_mint.key());
require!(
expected_pull_request_creator_reward_account.eq(&pull_request_creator_reward_account.key()),
DefiOSError::TokenAccountMismatch
);
require!(
pull_request.accepted,
DefiOSError::PullRequestNotYetAccepted
);
let issue_index_str = issue_account.index.to_string();
let repository_account_key = repository_account.key();
let issue_creator_key = issue_account.issue_creator.key();
let signer_seeds: &[&[&[u8]]] = &[&[
b"issue",
issue_index_str.as_bytes(),
repository_account_key.as_ref(),
issue_creator_key.as_ref(),
&[issue_account.bump],
]];
let issue_token_balance = issue_token_pool_account.amount;
require!(issue_token_balance > 0, DefiOSError::NoMoneyStakedOnIssue);
if issue_token_balance > 0 {
transfer(
CpiContext::new_with_signer(
token_program.to_account_info(),
Transfer {
from: issue_token_pool_account.to_account_info(),
to: pull_request_creator_reward_account.to_account_info(),
authority: issue_account.to_account_info(),
},
signer_seeds,
),
issue_token_balance,
)?;
};
emit!(RewardClaimed {
reward_claimmee: pull_request_creator.key(),
reward_amount: issue_token_balance,
pull_request: pull_request.key()
});
Ok(())
}