SUI Move合约实践——SUID简单流动性质押池 SUI -Staking Pool

  • Alan
  • 发布于 19小时前
  • 阅读 57

`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));
}
} 

`

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Alan
Alan
0x9cAD...0097
区块链BTC、ETH、BNB