`modulestaking_rewards::staking{usesui::object::{Self,ID,UID};usesui::transfer;usesui::tx_context::{Self,TxContext};usesui::balance::{Se
`
module staking_rewards::staking {
use sui::object::{Self, ID, UID};
use sui::transfer;
use sui::tx_context::{Self, TxContext};
use sui::balance::{Self, Balance};
use sui::coin::{Self, Coin};
use sui::clock::{Self, Clock};
use std::option::{Self, Option};
// 错误码
const ENO_REWARDS_TOKEN: u64 = 0;
const ENO_PERMISSION: u64 = 1;
const EZERO_AMOUNT: u64 = 2;
const EREWARD_DURATION_NOT_FINISHED: u64 = 3;
const EREWARD_RATE_ZERO: u64 = 4;
const EREWARD_TOO_HIGH: u64 = 5;
// 常量
const SCALE: u64 = 1000000; // 用于处理小数
struct StakingPool<phantom StakeToken, phantom RewardToken> has key {
id: UID,
owner: address,
staking_supply: Balance<StakeToken>,
rewards_supply: Balance<RewardToken>,
total_staked: u64,
duration: u64,
finish_at: u64,
updated_at: u64,
reward_rate: u64,
reward_per_token_stored: u64,
}
struct StakeRecord<phantom StakeToken, phantom RewardToken> has key {
id: UID,
owner: address,
pool_id: ID,
amount: u64,
reward_per_token_paid: u64,
rewards: u64,
}
// 创建质押池
public fun create_pool<StakeToken, RewardToken>(
clock: &Clock,
ctx: &mut TxContext
) {
let pool = StakingPool<StakeToken, RewardToken> {
id: object::new(ctx),
owner: tx_context::sender(ctx),
staking_supply: balance::zero(),
rewards_supply: balance::zero(),
total_staked: 0,
duration: 0,
finish_at: 0,
updated_at: clock::timestamp_ms(clock),
reward_rate: 0,
reward_per_token_stored: 0,
};
transfer::share_object(pool);
}
// 质押代币
public fun stake<StakeToken, RewardToken>(
pool: &mut StakingPool<StakeToken, RewardToken>,
clock: &Clock,
stake_coin: Coin<StakeToken>,
ctx: &mut TxContext
) {
let amount = coin::value(&stake_coin);
assert!(amount > 0, EZERO_AMOUNT);
// 更新奖励
update_reward(pool, clock, tx_context::sender(ctx));
// 转移质押代币
let stake_balance = coin::into_balance(stake_coin);
balance::join(&mut pool.staking_supply, stake_balance);
// 更新状态
pool.total_staked = pool.total_staked + amount;
// 创建质押记录
let record = StakeRecord<StakeToken, RewardToken> {
id: object::new(ctx),
owner: tx_context::sender(ctx),
pool_id: object::id(pool),
amount,
reward_per_token_paid: pool.reward_per_token_stored,
rewards: 0,
};
transfer::transfer(record, tx_context::sender(ctx));
}
// 提取质押
public fun withdraw<StakeToken, RewardToken>(
pool: &mut StakingPool<StakeToken, RewardToken>,
clock: &Clock,
record: &mut StakeRecord<StakeToken, RewardToken>,
amount: u64,
ctx: &mut TxContext
) {
assert!(amount > 0 && amount <= record.amount, EZERO_AMOUNT);
assert!(record.owner == tx_context::sender(ctx), ENO_PERMISSION);
// 更新奖励
update_reward(pool, clock, tx_context::sender(ctx));
// 更新状态
record.amount = record.amount - amount;
pool.total_staked = pool.total_staked - amount;
// 转出质押代币
let withdraw_coin = coin::from_balance(
balance::split(&mut pool.staking_supply, amount),
ctx
);
transfer::transfer(withdraw_coin, tx_context::sender(ctx));
}
// 领取奖励
public fun claim_reward<StakeToken, RewardToken>(
pool: &mut StakingPool<StakeToken, RewardToken>,
clock: &Clock,
record: &mut StakeRecord<StakeToken, RewardToken>,
ctx: &mut TxContext
) {
assert!(record.owner == tx_context::sender(ctx), ENO_PERMISSION);
// 更新奖励
update_reward(pool, clock, tx_context::sender(ctx));
let reward = record.rewards;
if (reward > 0) {
record.rewards = 0;
let reward_coin = coin::from_balance(
balance::split(&mut pool.rewards_supply, reward),
ctx
);
transfer::transfer(reward_coin, tx_context::sender(ctx));
}
}
// 内部函数:更新奖励
fun update_reward<StakeToken, RewardToken>(
pool: &mut StakingPool<StakeToken, RewardToken>,
clock: &Clock,
account: address,
) {
pool.reward_per_token_stored = reward_per_token(pool, clock);
pool.updated_at = last_time_reward_applicable(pool, clock);
// 更新用户奖励
let earned = earned(pool, clock, account);
// TODO: 更新用户奖励记录
}
// 内部函数:计算每个代币的奖励
fun reward_per_token<StakeToken, RewardToken>(
pool: &StakingPool<StakeToken, RewardToken>,
clock: &Clock,
): u64 {
if (pool.total_staked == 0) {
return pool.reward_per_token_stored
};
let time_delta = last_time_reward_applicable(pool, clock) - pool.updated_at;
pool.reward_per_token_stored +
((pool.reward_rate * time_delta * SCALE) / pool.total_staked)
}
// 内部函数:计算已赚取的奖励
fun earned<StakeToken, RewardToken>(
pool: &StakingPool<StakeToken, RewardToken>,
clock: &Clock,
account: address,
): u64 {
// TODO: 需要从StakeRecord中获取用户的质押信息
// 这里简化处理,实际实现需要查找用户的StakeRecord对象
0
}
// 内部函数:获取最后一次可用的奖励时间
fun last_time_reward_applicable<StakeToken, RewardToken>(
pool: &StakingPool<StakeToken, RewardToken>,
clock: &Clock,
): u64 {
let current_time = clock::timestamp_ms(clock);
if (current_time < pool.finish_at) {
current_time
} else {
pool.finish_at
}
}
// 设置奖励持续时间
public fun set_rewards_duration<StakeToken, RewardToken>(
pool: &mut StakingPool<StakeToken, RewardToken>,
clock: &Clock,
duration: u64,
ctx: &TxContext
) {
assert!(tx_context::sender(ctx) == pool.owner, ENO_PERMISSION);
assert!(clock::timestamp_ms(clock) >= pool.finish_at, EREWARD_DURATION_NOT_FINISHED);
pool.duration = duration;
}
// 通知奖励金额
public fun notify_reward_amount<StakeToken, RewardToken>(
pool: &mut StakingPool<StakeToken, RewardToken>,
clock: &Clock,
reward_coin: Coin<RewardToken>,
ctx: &TxContext
) {
assert!(tx_context::sender(ctx) == pool.owner, ENO_PERMISSION);
let current_time = clock::timestamp_ms(clock);
let reward_amount = coin::value(&reward_coin);
// 将奖励代币加入池中
let reward_balance = coin::into_balance(reward_coin);
balance::join(&mut pool.rewards_supply, reward_balance);
if (current_time >= pool.finish_at) {
pool.reward_rate = reward_amount / pool.duration;
} else {
let remaining_rewards = (pool.finish_at - current_time) * pool.reward_rate;
pool.reward_rate = (reward_amount + remaining_rewards) / pool.duration;
};
assert!(pool.reward_rate > 0, EREWARD_RATE_ZERO);
// 确保奖励金额不超过池子余额
let total_reward = pool.reward_rate * pool.duration;
assert!(total_reward <= balance::value(&pool.rewards_supply), EREWARD_TOO_HIGH);
pool.finish_at = current_time + pool.duration;
pool.updated_at = current_time;
// 更新奖励
update_reward(pool, clock, tx_context::sender(ctx));
}
}
`
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!