From 48ce3d2855267be933889a891497a4e62de0ec93 Mon Sep 17 00:00:00 2001 From: mx <53249469+mx819812523@users.noreply.github.com> Date: Tue, 21 Jan 2025 17:11:35 +0800 Subject: [PATCH] Fix liquidity incentive (#3217) * fix: add end time for liquidity incentive * fix: remove unuse import * fix: withdraw incentive * fix: modify endtime when update reward coin --- .../sources/liquidity_incentive.move | 89 +++++++++++-------- 1 file changed, 51 insertions(+), 38 deletions(-) diff --git a/apps/rooch_dex/sources/liquidity_incentive.move b/apps/rooch_dex/sources/liquidity_incentive.move index 1bee1433fc..42c48fb1cc 100644 --- a/apps/rooch_dex/sources/liquidity_incentive.move +++ b/apps/rooch_dex/sources/liquidity_incentive.move @@ -4,7 +4,7 @@ module rooch_dex::liquidity_incentive { use std::signer::address_of; - use app_admin::admin::AdminCap; + use std::u64; use moveos_std::table; use rooch_framework::coin; use moveos_std::table::{Table, new}; @@ -42,6 +42,7 @@ module rooch_dex::liquidity_incentive { const ErrorFarmingNotAlive: u64 = 7; const ErrorFarmingAliveStateInvalid: u64 = 8; const ErrorFarmingNotStake: u64 = 9; + const ErrorNotCreator: u64 = 10; const EXP_MAX_SCALE: u128 = 9; @@ -117,6 +118,7 @@ module rooch_dex::liquidity_incentive { struct FarmingAsset has key, store { + creator: address, asset_total_weight: u128, harvest_index: u128, last_update_timestamp: u64, @@ -124,6 +126,7 @@ module rooch_dex::liquidity_incentive { release_per_second: u128, // Start time, by seconds, user can operate stake only after this timestamp start_time: u64, + end_time: u64, coin_store: Object>, stake_info: Table>, // Representing the pool is alive, false: not alive, true: alive. @@ -143,29 +146,58 @@ module rooch_dex::liquidity_incentive { release_per_second: u128, coin_amount: u256, start_time: u64, - admin: &mut Object ){ let reward_coin = account_coin_store::withdraw(account, coin_amount); - create_pool_with_coin(release_per_second, reward_coin, start_time, admin) + create_pool_with_coin(account, release_per_second, reward_coin, start_time) + } + + public entry fun add_incentive( + account: &signer, + farming_asset_obj: &mut Object>, + coin_amount: u256, + ){ + let reward_coin = account_coin_store::withdraw(account, coin_amount); + let farming_asset = object::borrow_mut(farming_asset_obj); + coin_store::deposit(&mut farming_asset.coin_store, reward_coin); + assert!(farming_asset.end_time >= now_seconds(), ErrorFarmingNotAlive); + let end_time = (coin_amount / (farming_asset.release_per_second as u256) as u64); + farming_asset.end_time = farming_asset.end_time + end_time + } + + public entry fun withdraw_incentive( + account: &signer, + farming_asset_obj: &mut Object>, + coin_amount: u256, + ){ + + let farming_asset = object::borrow_mut(farming_asset_obj); + assert!(address_of(account) == farming_asset.creator, ErrorNotCreator); + let coin = coin_store::withdraw(&mut farming_asset.coin_store, coin_amount); + account_coin_store::deposit(farming_asset.creator, coin); + let end_time = (coin_amount / (farming_asset.release_per_second as u256) as u64); + farming_asset.end_time = farming_asset.end_time - end_time } /// Add asset pools public fun create_pool_with_coin( + account: &signer, release_per_second: u128, coin: Coin, start_time: u64, - _admin: &mut Object ) { + let end_time = (coin::value(&coin) / (release_per_second as u256) as u64); let coin_store = coin_store::create_coin_store(); coin_store::deposit(&mut coin_store, coin); if (swap_utils::sort_token_type()) { let farming_asset = object::new(FarmingAsset { + creator: address_of(account), asset_total_weight: 0, harvest_index: 0, last_update_timestamp: start_time, release_per_second, start_time, + end_time, coin_store, stake_info: new(), alive: true @@ -173,11 +205,13 @@ module rooch_dex::liquidity_incentive { object::to_shared(farming_asset) }else { let farming_asset = object::new(FarmingAsset { + creator: address_of(account), asset_total_weight: 0, harvest_index: 0, last_update_timestamp: start_time, release_per_second, start_time, + end_time, coin_store, stake_info: new(), alive: true @@ -186,32 +220,6 @@ module rooch_dex::liquidity_incentive { }; } - public fun modify_parameter( - release_per_second: u128, - alive: bool, - farming_asset_obj: &mut Object>, - _admin: &mut Object - ) { - // Not support to shuttingdown alive state. - assert!(alive, ErrorFarmingAliveStateInvalid); - - let farming_asset = object::borrow_mut>(farming_asset_obj); - - let now_seconds = now_seconds(); - - farming_asset.release_per_second = release_per_second; - farming_asset.last_update_timestamp = now_seconds; - - // if the pool is alive, then update index - if (farming_asset.alive) { - farming_asset.harvest_index = calculate_harvest_index_with_asset( - farming_asset, - now_seconds - ); - }; - farming_asset.alive = alive; - } - /// Call by stake user, staking amount of asset in order to get yield farming token public entry fun stake( signer: &signer, @@ -236,6 +244,7 @@ module rooch_dex::liquidity_incentive { // Check locking time let now_seconds = now_seconds(); assert!(farming_asset.start_time <= now_seconds, ErrorFarmingNotStillFreeze); + assert!(farming_asset.end_time > now_seconds, ErrorFarmingNotStillFreeze); let time_period = now_seconds - farming_asset.last_update_timestamp; @@ -298,7 +307,7 @@ module rooch_dex::liquidity_incentive { let Stake { last_harvest_index, asset_weight, asset, gain } = table::remove(&mut farming_asset.stake_info, signer::address_of(signer)); - let now_seconds = now_seconds(); + let now_seconds = u64::min(now_seconds(), farming_asset.end_time); let new_harvest_index = calculate_harvest_index_with_asset(farming_asset, now_seconds); let period_gain = calculate_withdraw_amount(new_harvest_index, last_harvest_index, asset_weight); @@ -309,6 +318,7 @@ module rooch_dex::liquidity_incentive { // Update farm asset farming_asset.asset_total_weight = farming_asset.asset_total_weight - asset_weight; + farming_asset.last_update_timestamp = now_seconds; if (farming_asset.alive) { @@ -333,7 +343,7 @@ module rooch_dex::liquidity_incentive { ): Coin { let farming_asset = object::borrow_mut(farming_asset_obj); assert!(table::contains(&farming_asset.stake_info, signer::address_of(signer)), ErrorFarmingNotStake); - let now_seconds = now_seconds(); + let now_seconds = u64::min(now_seconds(), farming_asset.end_time); let new_harvest_index = calculate_harvest_index_with_asset(farming_asset, now_seconds); let stake = table::borrow_mut(&mut farming_asset.stake_info, signer::address_of(signer)); let period_gain = calculate_withdraw_amount( @@ -357,7 +367,7 @@ module rooch_dex::liquidity_incentive { } /// The user can quering all yield farming amount in any time and scene - public fun query_gov_token_amount( + public fun query_harvest_token_amount( account: address, farming_asset_obj: &Object> ): u128 { @@ -366,7 +376,7 @@ module rooch_dex::liquidity_incentive { return 0 }; let stake = table::borrow(&farming_asset.stake_info, account); - let now_seconds = now_seconds(); + let now_seconds = u64::min(now_seconds(), farming_asset.end_time); let new_harvest_index = calculate_harvest_index_with_asset( farming_asset, @@ -452,7 +462,8 @@ module rooch_dex::liquidity_incentive { asset_total_weight: u128, last_update_timestamp: u64, now_seconds: u64, - release_per_second: u128): u128 { + release_per_second: u128 + ): u128 { assert!(asset_total_weight > 0, ErrorFarmingTotalWeightIsZero); assert!(last_update_timestamp <= now_seconds, ErrorFarmingTimestampInvalid); @@ -494,11 +505,13 @@ module rooch_dex::liquidity_incentive { coin_store::deposit(&mut coin_store, lp_reward_coin); let farming_asset_obj = object::new( FarmingAsset { + creator: address_of(&sender), asset_total_weight: 0, harvest_index: 0, last_update_timestamp: now_seconds(), release_per_second: 100, start_time:now_seconds(), + end_time: now_seconds() + 10000, coin_store, stake_info: new(), alive: true @@ -506,15 +519,15 @@ module rooch_dex::liquidity_incentive { stake(&sender, 100, &mut farming_asset_obj); let seconds = 100; timestamp::fast_forward_seconds_for_test(seconds); - let reward_a = query_gov_token_amount(address_of(&sender), &farming_asset_obj); + let reward_a = query_harvest_token_amount(address_of(&sender), &farming_asset_obj); stake(&account_b, 100, &mut farming_asset_obj); let total_weight = query_total_stake(&farming_asset_obj); assert!(total_weight == 200, 1); assert!(reward_a == 10000, 2); timestamp::fast_forward_seconds_for_test(seconds); - reward_a = query_gov_token_amount(address_of(&sender), &farming_asset_obj); + reward_a = query_harvest_token_amount(address_of(&sender), &farming_asset_obj); assert!(reward_a == 15000, 3); - let reward_b = query_gov_token_amount(address_of(&account_b), &farming_asset_obj); + let reward_b = query_harvest_token_amount(address_of(&account_b), &farming_asset_obj); assert!(reward_b == 5000, 4); let reward_coin = do_harvest(&sender, &mut farming_asset_obj); assert!(coin::value(&reward_coin) == 15000, 5);