use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod staking {
use super::*;
pub fn stake(
ctx: Context<Stake>,
amount: u64,
) -> Result<()> {
let stake_account = &mut ctx.accounts.stake_account;
let clock = Clock::get()?;
stake_account.staked_amount = stake_account.staked_amount
.checked_add(amount)
.ok_or(ErrorCode::Overflow)?;
stake_account.last_stake_time = clock.unix_timestamp;
emit!(StakeEvent {
user: ctx.accounts.user.key(),
amount,
total_staked: stake_account.staked_amount,
timestamp: clock.unix_timestamp,
});
msg!("Staked {} tokens", amount);
Ok(())
}
pub fn unstake(
ctx: Context<Unstake>,
amount: u64,
) -> Result<()> {
let stake_account = &mut ctx.accounts.stake_account;
let clock = Clock::get()?;
require!(
stake_account.staked_amount >= amount,
ErrorCode::InsufficientStake
);
stake_account.staked_amount = stake_account.staked_amount
.checked_sub(amount)
.ok_or(ErrorCode::Underflow)?;
emit!(UnstakeEvent {
user: ctx.accounts.user.key(),
amount,
remaining_staked: stake_account.staked_amount,
timestamp: clock.unix_timestamp,
});
msg!("Unstaked {} tokens", amount);
Ok(())
}
pub fn claim_rewards(ctx: Context<ClaimRewards>) -> Result<()> {
let stake_account = &ctx.accounts.stake_account;
let clock = Clock::get()?;
let time_elapsed = clock.unix_timestamp - stake_account.last_stake_time;
let rewards = calculate_rewards(stake_account.staked_amount, time_elapsed);
emit!(RewardsClaimedEvent {
user: ctx.accounts.user.key(),
rewards,
timestamp: clock.unix_timestamp,
});
msg!("Claimed {} reward tokens", rewards);
Ok(())
}
}
#[derive(Accounts)]
pub struct Stake<'info> {
#[account(mut)]
pub stake_account: Account<'info, StakeAccount>,
pub user: Signer<'info>,
}
#[derive(Accounts)]
pub struct Unstake<'info> {
#[account(mut, has_one = user)]
pub stake_account: Account<'info, StakeAccount>,
pub user: Signer<'info>,
}
#[derive(Accounts)]
pub struct ClaimRewards<'info> {
#[account(has_one = user)]
pub stake_account: Account<'info, StakeAccount>,
pub user: Signer<'info>,
}
#[account]
#[derive(InitSpace)]
pub struct StakeAccount {
pub user: Pubkey,
pub staked_amount: u64,
pub last_stake_time: i64,
}
// Events
#[event]
pub struct StakeEvent {
pub user: Pubkey,
pub amount: u64,
pub total_staked: u64,
pub timestamp: i64,
}
#[event]
pub struct UnstakeEvent {
pub user: Pubkey,
pub amount: u64,
pub remaining_staked: u64,
pub timestamp: i64,
}
#[event]
pub struct RewardsClaimedEvent {
pub user: Pubkey,
pub rewards: u64,
pub timestamp: i64,
}
#[error_code]
pub enum ErrorCode {
#[msg("Insufficient staked tokens")]
InsufficientStake,
#[msg("Arithmetic overflow")]
Overflow,
#[msg("Arithmetic underflow")]
Underflow,
}
fn calculate_rewards(staked_amount: u64, time_elapsed: i64) -> u64 {
// Simple reward calculation: 10% APY
let annual_rate = 10; // 10%
let seconds_per_year = 365 * 24 * 60 * 60;
(staked_amount as u128 * time_elapsed as u128 * annual_rate as u128
/ (100 * seconds_per_year) as u128) as u64
}