From 88bb9811bf5b1cb48bc71ae380d767bc2530fb7b Mon Sep 17 00:00:00 2001 From: axiongsupra Date: Thu, 19 Dec 2024 01:39:51 -0500 Subject: [PATCH] Correct implementation --- .../aptos-stdlib/sources/fixed_point64.move | 14 +++++++ .../sources/pbo_delegation_pool.move | 16 +++++--- .../sources/vesting_without_staking.move | 40 ++++++++++++------- 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/aptos-move/framework/aptos-stdlib/sources/fixed_point64.move b/aptos-move/framework/aptos-stdlib/sources/fixed_point64.move index 48c7ae67b65ee..71ceaa9b8307a 100644 --- a/aptos-move/framework/aptos-stdlib/sources/fixed_point64.move +++ b/aptos-move/framework/aptos-stdlib/sources/fixed_point64.move @@ -56,6 +56,19 @@ module aptos_std::fixed_point64 { ensures result.value == x.value + y.value; } + /// Returns x / y. The result cannot be greater than MAX_U128. + public fun divide(x: FixedPoint64, y: FixedPoint64): FixedPoint64 { + let x_raw = get_raw_value(x); + let y_raw = get_raw_value(y); + // If it is divisable, return the result. If not, return the result + 1. + let result = (x_raw as u256) / (y_raw as u256); + if ((x_raw as u256) % (y_raw as u256) != 0) { + result = result + 1; + }; + assert!(result <= MAX_U128, ERATIO_OUT_OF_RANGE); + create_from_raw_value((result as u128)) + } + /// Multiply a u128 integer by a fixed-point number, truncating any /// fractional part of the product. This will abort if the product /// overflows. @@ -95,6 +108,7 @@ module aptos_std::fixed_point64 { create_from_raw_value((unscaled_product as u128)) } + /// Divide a u128 integer by a fixed-point number, truncating any /// fractional part of the quotient. This will abort if the divisor /// is zero or if the quotient overflows. diff --git a/aptos-move/framework/supra-framework/sources/pbo_delegation_pool.move b/aptos-move/framework/supra-framework/sources/pbo_delegation_pool.move index af5009f4c445c..c6ecefcbebbcb 100644 --- a/aptos-move/framework/supra-framework/sources/pbo_delegation_pool.move +++ b/aptos-move/framework/supra-framework/sources/pbo_delegation_pool.move @@ -122,6 +122,7 @@ module supra_framework::pbo_delegation_pool { use aptos_std::table::{Self, Table}; use aptos_std::smart_table::{Self, SmartTable}; use aptos_std::fixed_point64::{Self, FixedPoint64}; + use aptos_std::math64::min; use supra_framework::coin::Coin; use supra_framework::account; @@ -1778,12 +1779,15 @@ module supra_framework::pbo_delegation_pool { cfraction = fixed_point64::add(cfraction, next_fraction); last_unlocked_period = last_unlocked_period + 1; }; - - let final_fraction= *vector::borrow(&unlock_schedule.schedule, schedule_length - 1); - // Fast foward calculation to current period and don't update last_unlocked_period since it is not used anymore - cfraction = fixed_point64::add(cfraction, fixed_point64::multiply_u128_return_fixpoint64((unlock_periods_passed - last_unlocked_period as u128), final_fraction)); - cfraction = fixed_point64::min(cfraction, one); - + if (last_unlocked_period < unlock_periods_passed && fixed_point64::less(cfraction, one)) { + let final_fraction= *vector::borrow(&unlock_schedule.schedule, schedule_length - 1); + // Determine how many periods is needed + let periods_needed = min(unlock_periods_passed - last_unlocked_period, + ((fixed_point64::get_raw_value(fixed_point64::divide(fixed_point64::sub(one, cfraction), final_fraction)) as u64) ) + ); + // Acclerate calculation to current period and don't update last_unlocked_period since it is not used anymore + cfraction = fixed_point64::add(cfraction, fixed_point64::multiply_u128_return_fixpoint64((periods_needed as u128), final_fraction)); + }; unlock_schedule.cumulative_unlocked_fraction = cfraction; unlock_schedule.last_unlock_period = unlock_periods_passed; let unlockable_amount = cached_unlockable_balance(delegator_addr, pool_address); diff --git a/aptos-move/framework/supra-framework/sources/vesting_without_staking.move b/aptos-move/framework/supra-framework/sources/vesting_without_staking.move index 2be38d29d95e6..dd21e4e3235b9 100644 --- a/aptos-move/framework/supra-framework/sources/vesting_without_staking.move +++ b/aptos-move/framework/supra-framework/sources/vesting_without_staking.move @@ -496,8 +496,8 @@ module supra_framework::vesting_without_staking { // Index is 0-based while period is 1-based so we need to subtract 1. while (last_completed_period >= next_period_to_vest && vesting_record.left_amount > 0 && next_period_to_vest <= vector::length(schedule)) { - // let schedule_index = next_period_to_vest - 1; - let vesting_fraction = *vector::borrow(schedule, vector::length(schedule) - 1); + let schedule_index = next_period_to_vest - 1; + let vesting_fraction = *vector::borrow(schedule, schedule_index); vest_transfer(vesting_record, signer_cap, beneficiary, vesting_fraction); emit_event(&mut vesting_contract.vest_events, VestEvent { @@ -510,19 +510,29 @@ module supra_framework::vesting_without_staking { next_period_to_vest = next_period_to_vest + 1; }; - let final_fraction = *vector::borrow(schedule, vector::length(schedule) - 1); - let total_fraction = fixed_point32::multiply_u64_return_fixpoint32((last_completed_period - next_period_to_vest ), final_fraction); - // We don't need to check vesting_record.left_amount > 0 because vest_transfer will handle that. - vest_transfer(vesting_record, signer_cap, beneficiary, total_fraction); - next_period_to_vest = last_completed_period + 1; - emit_event(&mut vesting_contract.vest_events, - VestEvent { - admin: vesting_contract.admin, - shareholder_address: shareholder_address, - vesting_contract_address: contract_address, - period_vested: next_period_to_vest, - }, - ); + if(last_completed_period >= next_period_to_vest && vesting_record.left_amount > 0) { + let final_fraction = *vector::borrow(schedule, vector::length(schedule) - 1); + // Determine how many periods is needed based on the left_amount + let periods_need_used_up_amount = if (vesting_record.left_amount % fixed_point32::multiply_u64(vesting_record.init_amount, final_fraction) == 0) { + vesting_record.left_amount / fixed_point32::multiply_u64(vesting_record.init_amount, final_fraction) + } else { + vesting_record.left_amount / fixed_point32::multiply_u64(vesting_record.init_amount, final_fraction) + 1 + }; + let periods_needed = + min(periods_need_used_up_amount, last_completed_period - next_period_to_vest + 1); + let total_fraction = fixed_point32::multiply_u64_return_fixpoint32(periods_needed, final_fraction); + // We don't need to check vesting_record.left_amount > 0 because vest_transfer will handle that. + vest_transfer(vesting_record, signer_cap, beneficiary, total_fraction); + next_period_to_vest = next_period_to_vest + periods_needed; + emit_event(&mut vesting_contract.vest_events, + VestEvent { + admin: vesting_contract.admin, + shareholder_address: shareholder_address, + vesting_contract_address: contract_address, + period_vested: next_period_to_vest, + }, + ); + }; //update last_vested_period for the shareholder vesting_record.last_vested_period = next_period_to_vest - 1;