Skip to content

Commit

Permalink
Added vesting functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
psorinionut committed Jan 6, 2024
1 parent 6714a9d commit 47f0ea9
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 4 deletions.
61 changes: 59 additions & 2 deletions launchpad-guaranteed-tickets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
multiversx_sc::imports!();
multiversx_sc::derive_imports!();

use launchpad_common::launch_stage::Flags;
use launchpad_common::{launch_stage::Flags, tickets::WINNING_TICKET};

use crate::guranteed_ticket_winners::GuaranteedTicketsSelectionOperation;

pub mod guaranteed_tickets_init;
pub mod guranteed_ticket_winners;
pub mod token_release;

pub type UserTicketsStatus = MultiValue5<usize, usize, usize, usize, usize>;

Expand All @@ -27,6 +28,7 @@ pub trait LaunchpadGuaranteedTickets:
+ launchpad_common::user_interactions::UserInteractionsModule
+ guaranteed_tickets_init::GuaranteedTicketsInitModule
+ guranteed_ticket_winners::GuaranteedTicketWinnersModule
+ token_release::TokenReleaseModule
{
#[allow(clippy::too_many_arguments)]
#[init]
Expand Down Expand Up @@ -149,7 +151,62 @@ pub trait LaunchpadGuaranteedTickets:

#[endpoint(claimLaunchpadTokens)]
fn claim_launchpad_tokens_endpoint(&self) {
self.claim_launchpad_tokens(Self::default_send_launchpad_tokens_fn);
let caller = self.blockchain().get_caller();
let user_results_processed = self.claim_list().contains(&caller);
if !user_results_processed {
self.compute_launchpad_results(&caller);
};

let claimable_tokens = self.compute_claimable_tokens(&caller);
if claimable_tokens > 0 {
let launchpad_token_id = self.launchpad_token_id().get();
self.send()
.direct_esdt(&caller, &launchpad_token_id, 0, &claimable_tokens);
self.user_claimed_balance(&caller)
.update(|balance| *balance += claimable_tokens);
}
}

fn compute_launchpad_results(&self, caller: &ManagedAddress) {
self.require_claim_period();

let ticket_range = self.try_get_ticket_range(caller);
let nr_confirmed_tickets = self.nr_confirmed_tickets(caller).get();
let mut nr_redeemable_tickets = 0;

for ticket_id in ticket_range.first_id..=ticket_range.last_id {
let ticket_status = self.ticket_status(ticket_id).get();
if ticket_status == WINNING_TICKET {
self.ticket_status(ticket_id).clear();

nr_redeemable_tickets += 1;
}

self.ticket_pos_to_id(ticket_id).clear();
}

self.nr_confirmed_tickets(caller).clear();
self.ticket_range_for_address(caller).clear();
self.ticket_batch(ticket_range.first_id).clear();

if nr_redeemable_tickets > 0 {
self.nr_winning_tickets()
.update(|nr_winning_tickets| *nr_winning_tickets -= nr_redeemable_tickets);
}

self.claim_list().add(caller);

let nr_tickets_to_refund = nr_confirmed_tickets - nr_redeemable_tickets;
self.refund_ticket_payment(caller, nr_tickets_to_refund);

if nr_redeemable_tickets > 0 {
let tokens_per_winning_ticket = self.launchpad_tokens_per_winning_ticket().get();
let launchpad_tokens_amount_won =
BigUint::from(nr_redeemable_tickets as u32) * tokens_per_winning_ticket;

self.user_total_claimable_balance(caller)
.set(launchpad_tokens_amount_won);
}
}

#[only_owner]
Expand Down
126 changes: 126 additions & 0 deletions launchpad-guaranteed-tickets/src/token_release.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
multiversx_sc::imports!();
multiversx_sc::derive_imports!();

use launchpad_common::config;

pub const MAX_PERCENTAGE: u64 = 10_000;

#[derive(TopEncode, TopDecode, TypeAbi)]
pub struct UnlockSchedule {
claim_start_epoch: u64,
initial_release_percentage: u64,
vesting_release_times: u64,
vesting_release_percentage: u64,
vesting_release_period: u64,
}

impl UnlockSchedule {
pub fn new(
claim_start_epoch: u64,
initial_release_percentage: u64,
vesting_release_times: u64,
vesting_release_percentage: u64,
vesting_release_period: u64,
) -> Self {
UnlockSchedule {
claim_start_epoch,
initial_release_percentage,
vesting_release_times,
vesting_release_percentage,
vesting_release_period,
}
}
}

#[multiversx_sc::module]
pub trait TokenReleaseModule: config::ConfigModule {
#[only_owner]
#[endpoint(setUnlockSchedule)]
fn set_unlock_schedule(
&self,
claim_start_epoch: u64,
initial_release_percentage: u64,
vesting_release_times: u64,
vesting_release_percentage: u64,
vesting_release_period: u64,
) {
let configuration = self.configuration();
require!(
!configuration.is_empty(),
"Timeline configuration is not set"
);
let confirmation_period_start_block = configuration.get().confirmation_period_start_block;

let current_block = self.blockchain().get_block_nonce();
let current_epoch = self.blockchain().get_block_epoch();
require!(
current_block < confirmation_period_start_block || self.unlock_schedule().is_empty(),
"Can't change the unlock schedule"
);
require!(
claim_start_epoch >= current_epoch,
"Wrong claim start epoch"
);
require!(
vesting_release_period > 0,
"Wrong vesting release recurrency"
);

let unlock_percentage =
initial_release_percentage + vesting_release_times * vesting_release_percentage;

require!(
unlock_percentage == MAX_PERCENTAGE,
"Unlock percentage is not 100%"
);

let unlock_schedule = UnlockSchedule::new(
claim_start_epoch,
initial_release_percentage,
vesting_release_times,
vesting_release_percentage,
vesting_release_period,
);

self.unlock_schedule().set(unlock_schedule);
}

#[view(getClaimableTokens)]
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();
if user_total_claimable_balance == user_claimed_balance {
return BigUint::zero();
}
let unlock_schedule_mapper = self.unlock_schedule();
if unlock_schedule_mapper.is_empty() {
return BigUint::zero();
}
let unlock_schedule = unlock_schedule_mapper.get();
let current_epoch = self.blockchain().get_block_epoch();
if unlock_schedule.claim_start_epoch > current_epoch {
return BigUint::zero();
}

let epochs_passed = current_epoch - unlock_schedule.claim_start_epoch;
let mut claimable_periods = epochs_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;

current_claimable_tokens - user_claimed_balance
}

#[storage_mapper("userTotalClaimableBalance")]
fn user_total_claimable_balance(&self, address: &ManagedAddress) -> SingleValueMapper<BigUint>;

#[storage_mapper("userClaimedBalance")]
fn user_claimed_balance(&self, address: &ManagedAddress) -> SingleValueMapper<BigUint>;

#[storage_mapper("unlockSchedule")]
fn unlock_schedule(&self) -> SingleValueMapper<UnlockSchedule>;
}
7 changes: 5 additions & 2 deletions launchpad-guaranteed-tickets/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
////////////////////////////////////////////////////

// Init: 1
// Endpoints: 32
// Endpoints: 35
// Async Callback (empty): 1
// Total number of exported functions: 34
// Total number of exported functions: 37

#![no_std]
#![feature(lang_items)]
Expand All @@ -21,6 +21,7 @@ multiversx_sc_wasm_adapter::endpoints! {
addTickets
depositLaunchpadTokens
addUsersToBlacklist
removeGuaranteedUsersFromBlacklist
distributeGuaranteedTickets
claimLaunchpadTokens
claimTicketPayment
Expand Down Expand Up @@ -50,6 +51,8 @@ multiversx_sc_wasm_adapter::endpoints! {
isUserBlacklisted
confirmTickets
hasUserClaimedTokens
setUnlockSchedule
getClaimableTokens
)
}

Expand Down

0 comments on commit 47f0ea9

Please sign in to comment.