From 3876b6328a06b4550094de1e6413a322e2386971 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Tue, 11 Jun 2024 02:07:04 +0300 Subject: [PATCH] Launchpad with custom unlock schedule --- .../src/token_release.rs | 107 ++++++++---------- launchpad/wasm/src/lib.rs | 2 +- 2 files changed, 47 insertions(+), 62 deletions(-) diff --git a/launchpad-guaranteed-tickets/src/token_release.rs b/launchpad-guaranteed-tickets/src/token_release.rs index bfebe0a..7535fd8 100644 --- a/launchpad-guaranteed-tickets/src/token_release.rs +++ b/launchpad-guaranteed-tickets/src/token_release.rs @@ -4,30 +4,19 @@ multiversx_sc::derive_imports!(); use launchpad_common::config; pub const MAX_PERCENTAGE: u64 = 10_000; +pub const MAX_VESTING_RELEASES: usize = 50; -#[derive(TopEncode, TopDecode, TypeAbi)] -pub struct UnlockSchedule { - claim_start_round: u64, - initial_release_percentage: u64, - vesting_release_times: u64, +#[derive(TypeAbi, ManagedVecItem, TopEncode, TopDecode, NestedEncode, NestedDecode)] +pub struct VestingRelease { + vesting_release_epoch: u64, vesting_release_percentage: u64, - vesting_release_period: u64, } -impl UnlockSchedule { - pub fn new( - claim_start_round: u64, - initial_release_percentage: u64, - vesting_release_times: u64, - vesting_release_percentage: u64, - vesting_release_period: u64, - ) -> Self { - UnlockSchedule { - claim_start_round, - initial_release_percentage, - vesting_release_times, +impl VestingRelease { + pub fn new(vesting_release_epoch: u64, vesting_release_percentage: u64) -> Self { + VestingRelease { + vesting_release_epoch, vesting_release_percentage, - vesting_release_period, } } } @@ -36,14 +25,7 @@ impl UnlockSchedule { pub trait TokenReleaseModule: config::ConfigModule { #[only_owner] #[endpoint(setUnlockSchedule)] - fn set_unlock_schedule( - &self, - claim_start_round: u64, - initial_release_percentage: u64, - vesting_release_times: u64, - vesting_release_percentage: u64, - vesting_release_period: u64, - ) { + fn set_unlock_schedule(&self, vesting_releases: MultiValueEncoded>) { let configuration = self.configuration(); require!( !configuration.is_empty(), @@ -52,36 +34,41 @@ pub trait TokenReleaseModule: config::ConfigModule { let confirmation_period_start_block = configuration.get().confirmation_period_start_block; let current_block = self.blockchain().get_block_nonce(); - let current_round = self.blockchain().get_block_round(); require!( current_block < confirmation_period_start_block || self.unlock_schedule().is_empty(), "Can't change the unlock schedule" ); require!( - claim_start_round >= current_round, - "Wrong claim start round" - ); - require!( - vesting_release_period > 0 || initial_release_percentage == MAX_PERCENTAGE, - "Wrong vesting release recurrency" + !vesting_releases.is_empty() && vesting_releases.len() <= MAX_VESTING_RELEASES, + "Wrong release schedule" ); - let unlock_percentage = - initial_release_percentage + vesting_release_times * vesting_release_percentage; + let mut unlock_schedule = ManagedVec::new(); + let mut total_unlock_percentage = 0; + let mut last_release_epoch = self.blockchain().get_block_epoch(); + + for vesting_release in vesting_releases { + let (vesting_release_epoch, vesting_release_percentage) = vesting_release.into_tuple(); + + require!( + vesting_release_epoch >= last_release_epoch, + "The release epochs must be in order" + ); + + total_unlock_percentage += vesting_release_percentage; + last_release_epoch = vesting_release_epoch; + + unlock_schedule.push(VestingRelease::new( + vesting_release_epoch, + vesting_release_percentage, + )); + } require!( - unlock_percentage == MAX_PERCENTAGE, + total_unlock_percentage == MAX_PERCENTAGE, "Unlock percentage is not 100%" ); - let unlock_schedule = UnlockSchedule::new( - claim_start_round, - initial_release_percentage, - vesting_release_times, - vesting_release_percentage, - vesting_release_period, - ); - self.unlock_schedule().set(unlock_schedule); } @@ -89,6 +76,10 @@ pub trait TokenReleaseModule: config::ConfigModule { fn compute_claimable_tokens(&self, address: &ManagedAddress) -> BigUint { let user_total_claimable_balance = self.user_total_claimable_balance(address).get(); let user_claimed_balance = self.user_claimed_balance(address).get(); + require!( + user_total_claimable_balance > 0, + "User has no claimable tokens" + ); require!( user_claimed_balance < user_total_claimable_balance, "Already claimed all tokens" @@ -99,24 +90,18 @@ pub trait TokenReleaseModule: config::ConfigModule { return BigUint::zero(); } let unlock_schedule = unlock_schedule_mapper.get(); - let current_round = self.blockchain().get_block_round(); - if unlock_schedule.claim_start_round > current_round { - return BigUint::zero(); - } - - if unlock_schedule.initial_release_percentage == MAX_PERCENTAGE { - return user_total_claimable_balance; + let current_epoch = self.blockchain().get_block_epoch(); + let mut current_claimable_percentage = 0; + for vesting_release in unlock_schedule.iter() { + if vesting_release.vesting_release_epoch < current_epoch { + break; + } + + current_claimable_percentage += vesting_release.vesting_release_percentage; } - let rounds_passed = current_round - unlock_schedule.claim_start_round; - let mut claimable_periods = rounds_passed / unlock_schedule.vesting_release_period; - if claimable_periods > unlock_schedule.vesting_release_times { - claimable_periods = unlock_schedule.vesting_release_times; - } - let claimable_percentage = unlock_schedule.initial_release_percentage - + unlock_schedule.vesting_release_percentage * claimable_periods; let current_claimable_tokens = - &user_total_claimable_balance * claimable_percentage / MAX_PERCENTAGE; + &user_total_claimable_balance * current_claimable_percentage / MAX_PERCENTAGE; current_claimable_tokens - user_claimed_balance } @@ -131,5 +116,5 @@ pub trait TokenReleaseModule: config::ConfigModule { #[view(getUnlockSchedule)] #[storage_mapper("unlockSchedule")] - fn unlock_schedule(&self) -> SingleValueMapper; + fn unlock_schedule(&self) -> SingleValueMapper>; } diff --git a/launchpad/wasm/src/lib.rs b/launchpad/wasm/src/lib.rs index 69c76ac..9f3177a 100644 --- a/launchpad/wasm/src/lib.rs +++ b/launchpad/wasm/src/lib.rs @@ -29,7 +29,7 @@ multiversx_sc_wasm_adapter::endpoints! { getLaunchpadTokensPerWinningTicket getTicketPrice getNumberOfWinningTickets - getTotalNumberOfWinningTickets + getTotalLaunchpadTokensDeposited setTicketPrice setLaunchpadTokensPerWinningTicket setConfirmationPeriodStartBlock