Kод смарт-контракта на Rust + Anchor:
pub fn initialize(ctx: Context<Initialize>, reward_rate: u64) -> Result<()> {
let staking_account = &mut ctx.accounts.staking_account;
staking_account.reward_rate = reward_rate;
staking_account.total_staked = 0;
Ok(())
}
pub fn stake(ctx: Context<Stake>, amount: u64) -> Result<()> {
let staking_account = &mut ctx.accounts.staking_account;
let user_staking = &mut ctx.accounts.user_staking;
user_staking.amount += amount;
staking_account.total_staked += amount;
user_staking.start_time = Clock::get()?.unix_timestamp;
token::transfer(ctx.accounts.into_transfer_context(), amount)?;
Ok(())
}
pub fn unstake(ctx: Context<Unstake>) -> Result<()> {
let staking_account = &mut ctx.accounts.staking_account;
let user_staking = &mut ctx.accounts.user_staking;
let current_time = Clock::get()?.unix_timestamp;
let duration = current_time - user_staking.start_time;
let base_reward = user_staking.amount * staking_account.reward_rate * duration as u64;
let scaled_reward = base_reward / (1_000_000 + duration as u64); // Smooth scaling to prevent excessive rewards
token::transfer(ctx.accounts.into_transfer_back_context(), user_staking.amount + scaled_reward)?;
staking_account.total_staked -= user_staking.amount;
user_staking.amount = 0;
Ok(())
}
Tесты для проверки функционала стейкинга и анстейкинга, включая расчёт наград.
#[test]
fn test_stake_unstake() {
let mut staking_account = StakingAccount { reward_rate: 10, total_staked: 0 };
let mut user_staking = UserStaking { amount: 0, start_time: 0 };
let amount = 100;
let timestamp = 1_000_000;
user_staking.amount += amount;
staking_account.total_staked += amount;
user_staking.start_time = timestamp;
assert_eq!(user_staking.amount, 100);
assert_eq!(staking_account.total_staked, 100);
let duration = 1_000_000;
let base_reward = user_staking.amount * staking_account.reward_rate * duration as u64;
let scaled_reward = base_reward / (1_000_000 + duration as u64);
staking_account.total_staked -= user_staking.amount;
user_staking.amount = 0;
assert_eq!(user_staking.amount, 0);
assert_eq!(staking_account.total_staked, 0);
assert_eq!(scaled_reward, 999); // Adjusted for smooth scaling
}
Last updated