Skip to content

Commit

Permalink
Merge pull request #5 from multiversx/unbond
Browse files Browse the repository at this point in the history
Unbond tokens
  • Loading branch information
dorin-iancu authored Apr 29, 2024
2 parents 9712e77 + 7f8cc18 commit 873d355
Show file tree
Hide file tree
Showing 11 changed files with 318 additions and 94 deletions.
8 changes: 7 additions & 1 deletion gravity-restaking/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![no_std]

use user_actions::sovereign::Epoch;

multiversx_sc::imports!();

pub mod token_whitelist;
Expand All @@ -14,10 +16,14 @@ pub trait GravityRestaking:
+ user_actions::validator::ValidatorModule
+ user_actions::sovereign::SovereignModule
+ user_actions::common_actions::CommonActionsModule
+ user_actions::common_storage::CommonStorageModule
+ user_actions::unbond::UnbondModule
+ utils::UtilsModule
{
#[init]
fn init(&self) {}
fn init(&self, unbond_epochs: Epoch) {
self.set_unbond_epochs(unbond_epochs);
}

#[upgrade]
fn upgrade(&self) {}
Expand Down
53 changes: 52 additions & 1 deletion gravity-restaking/src/unique_payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,17 @@ use mergeable::Mergeable;

pub type PaymentsVec<M> = ManagedVec<M, EsdtTokenPayment<M>>;

#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Clone, PartialEq, Debug)]
#[derive(
TypeAbi,
TopEncode,
TopDecode,
NestedEncode,
NestedDecode,
Clone,
PartialEq,
Debug,
ManagedVecItem,
)]
pub struct UniquePayments<M: ManagedTypeApi> {
payments: PaymentsVec<M>,
}
Expand Down Expand Up @@ -97,3 +107,44 @@ impl<M: ManagedTypeApi> UniquePayments<M> {
self.payments
}
}

impl<M: ManagedTypeApi> Mergeable<M> for UniquePayments<M> {
#[inline]
fn can_merge_with(&self, _other: &Self) -> bool {
true
}

fn merge_with(&mut self, mut other: Self) {
self.error_if_not_mergeable(&other);

if self.payments.is_empty() {
self.payments = other.payments;
return;
}
if other.payments.is_empty() {
return;
}

let first_len = self.payments.len();
let mut second_len = other.payments.len();
for i in 0..first_len {
let mut current_payment = self.payments.get(i);
for j in 0..second_len {
let other_payment = other.payments.get(j);
if !current_payment.can_merge_with(&other_payment) {
continue;
}

current_payment.amount += other_payment.amount;
let _ = self.payments.set(i, &current_payment);

other.payments.remove(j);
second_len -= 1;

break;
}
}

self.payments.append_vec(other.payments);
}
}
2 changes: 2 additions & 0 deletions gravity-restaking/src/user_actions/call_delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ pub trait CallDelegationModule:
+ crate::token_whitelist::TokenWhitelistModule
+ super::validator::ValidatorModule
+ super::sovereign::SovereignModule
+ super::unbond::UnbondModule
+ super::common_actions::CommonActionsModule
+ super::common_storage::CommonStorageModule
+ utils::UtilsModule
{
#[endpoint(moveStakeToReStaking)]
Expand Down
12 changes: 5 additions & 7 deletions gravity-restaking/src/user_actions/common_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ pub struct RemoveDelegationArgs<'a, S: StorageMapperApi> {
pub total_by_user_mapper: SingleValueMapper<S, BigUint<S>>,
pub all_delegators_mapper: &'a mut UnorderedSetMapper<S, AddressId>,
pub delegated_by_mapper: SingleValueMapper<S, UniquePayments<S>>,
pub user_tokens_mapper: SingleValueMapper<S, UniquePayments<S>>,
pub tokens: PaymentsMultiValue<S>,
pub caller_id: AddressId,
}
Expand Down Expand Up @@ -84,7 +83,10 @@ pub trait CommonActionsModule: crate::token_whitelist::TokenWhitelistModule {
args.delegated_by_mapper.set(tokens_delegated_by_user);
}

fn remove_delegation(&self, args: RemoveDelegationArgs<Self::Api>) {
fn remove_delegation(
&self,
args: RemoveDelegationArgs<Self::Api>,
) -> UniquePayments<Self::Api> {
require!(!args.delegated_by_mapper.is_empty(), "Nothing delegated");

let mut output_payments = PaymentsVec::new();
Expand Down Expand Up @@ -114,10 +116,6 @@ pub trait CommonActionsModule: crate::token_whitelist::TokenWhitelistModule {
}
});

args.user_tokens_mapper.update(|user_tokens| {
for payment in &output_payments {
user_tokens.add_payment(payment);
}
});
UniquePayments::new_from_payments(output_payments)
}
}
13 changes: 13 additions & 0 deletions gravity-restaking/src/user_actions/common_storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use crate::unique_payments::UniquePayments;

multiversx_sc::imports!();

#[multiversx_sc::module]
pub trait CommonStorageModule {
#[storage_mapper("userIds")]
fn user_ids(&self) -> AddressToIdMapper<Self::Api>;

#[view(getUserTokens)]
#[storage_mapper("userTokens")]
fn user_tokens(&self, user_id: AddressId) -> SingleValueMapper<UniquePayments<Self::Api>>;
}
2 changes: 2 additions & 0 deletions gravity-restaking/src/user_actions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pub mod call_delegation;
pub mod common_actions;
pub mod common_storage;
pub mod sovereign;
pub mod unbond;
pub mod user;
pub mod validator;
39 changes: 38 additions & 1 deletion gravity-restaking/src/user_actions/sovereign.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::unique_payments::UniquePayments;

use super::common_actions::AddDelegationArgs;

multiversx_sc::imports!();
multiversx_sc::derive_imports!();

Expand All @@ -19,7 +21,12 @@ impl<M: ManagedTypeApi> SovereignInfo<M> {
}

#[multiversx_sc::module]
pub trait SovereignModule: utils::UtilsModule {
pub trait SovereignModule:
crate::token_whitelist::TokenWhitelistModule
+ crate::user_actions::common_actions::CommonActionsModule
+ crate::user_actions::common_storage::CommonStorageModule
+ utils::UtilsModule
{
#[endpoint(registerSov)]
fn register_sov(&self, name: ManagedBuffer, description: ManagedBuffer) {
self.require_not_empty_buffer(&name);
Expand Down Expand Up @@ -66,6 +73,36 @@ pub trait SovereignModule: utils::UtilsModule {
// TODO
}

#[payable("*")]
#[endpoint(addOwnSecurityFunds)]
fn add_own_security_funds(&self) {
let sov_chain = self.blockchain().get_caller();
let sov_id = self.sovereign_id().get_id_non_zero(&sov_chain);
let user_id_of_sov_chain = self.user_ids().get_id_or_insert(&sov_chain);

let payments = self.get_non_empty_payments();
let mut total = BigUint::zero();
for payment in &payments {
self.require_token_in_whitelist(&payment.token_identifier);

total += self.get_total_staked_egld(&payment.token_identifier, &payment.amount);
}

let args = AddDelegationArgs {
total_delegated_mapper: self.total_delegated_sov_amount(sov_id),
total_by_user_mapper: self.total_sov_by_user(user_id_of_sov_chain, sov_id),
all_delegators_mapper: &mut self.all_sov_delegators(sov_id),
delegated_by_mapper: self.delegated_sov_by(user_id_of_sov_chain, sov_id),
opt_validator_config_mapper: None,
payments_to_add: payments,
total_amount: total,
caller_id: user_id_of_sov_chain,
};
self.add_delegation(args);

// TODO: event
}

#[view(getSovInfo)]
fn get_sov_info(&self, sov_address: ManagedAddress) -> SovereignInfo<Self::Api> {
let sov_id = self.sovereign_id().get_id_non_zero(&sov_address);
Expand Down
115 changes: 115 additions & 0 deletions gravity-restaking/src/user_actions/unbond.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use mergeable::Mergeable;

use crate::unique_payments::UniquePayments;

use super::sovereign::Epoch;

multiversx_sc::imports!();
multiversx_sc::derive_imports!();

#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem)]
pub struct UnbondInfo<M: ManagedTypeApi> {
pub tokens: UniquePayments<M>,
pub unbond_epoch: Epoch,
}

impl<M: ManagedTypeApi> UnbondInfo<M> {
#[inline]
pub fn new(tokens: UniquePayments<M>, unbond_epoch: Epoch) -> Self {
Self {
tokens,
unbond_epoch,
}
}
}

impl<M: ManagedTypeApi> Mergeable<M> for UnbondInfo<M> {
fn can_merge_with(&self, other: &Self) -> bool {
self.unbond_epoch == other.unbond_epoch
}

fn merge_with(&mut self, other: Self) {
self.error_if_not_mergeable(&other);

self.tokens.merge_with(other.tokens);
}
}

#[multiversx_sc::module]
pub trait UnbondModule: super::common_storage::CommonStorageModule {
#[only_owner]
#[endpoint(setUnbondEpochs)]
fn set_unbond_epochs(&self, unbond_epochs: Epoch) {
self.unbond_epochs().set(unbond_epochs);
}

#[view(getUserUnbondInfo)]
fn get_user_unbond_info(&self, user: ManagedAddress) -> ManagedVec<UnbondInfo<Self::Api>> {
let user_id = self.user_ids().get_id_non_zero(&user);

self.unbond_info(user_id).get()
}

fn add_unbond_tokens(&self, user_id: AddressId, tokens: UniquePayments<Self::Api>) {
let unbond_epochs = self.unbond_epochs().get();
let current_epoch = self.blockchain().get_block_epoch();
let final_unbond_epoch = current_epoch + unbond_epochs;
let mut current_unbond_info = UnbondInfo::new(tokens, final_unbond_epoch);

let unbond_mapper = self.unbond_info(user_id);
if unbond_mapper.is_empty() {
unbond_mapper.set(ManagedVec::from_single_item(current_unbond_info));

return;
}

let mut all_user_unbonds = unbond_mapper.get();
for (i, unbond_info) in all_user_unbonds.iter().enumerate() {
if !current_unbond_info.can_merge_with(&unbond_info) {
continue;
}

current_unbond_info.merge_with(unbond_info);
let _ = all_user_unbonds.set(i, &current_unbond_info);
unbond_mapper.set(all_user_unbonds);

return;
}

all_user_unbonds.push(current_unbond_info);
unbond_mapper.set(all_user_unbonds);
}

fn unbond_tokens_common(&self, user_id: AddressId) -> UniquePayments<Self::Api> {
let mut result = UniquePayments::new();

let current_epoch = self.blockchain().get_block_epoch();
self.unbond_info(user_id).update(|user_unbond_info| {
let mut i = 0;
let mut vec_len = user_unbond_info.len();
while vec_len > 0 && i < vec_len {
let current_unbond_info = user_unbond_info.get(i);
if current_unbond_info.unbond_epoch > current_epoch {
i += 1;

continue;
}

result.merge_with(current_unbond_info.tokens);
user_unbond_info.remove(0);
vec_len -= 1;
}
});

result
}

#[storage_mapper("unbondEpochs")]
fn unbond_epochs(&self) -> SingleValueMapper<Epoch>;

#[storage_mapper("unbondTokens")]
fn unbond_info(
&self,
user_id: AddressId,
) -> SingleValueMapper<ManagedVec<UnbondInfo<Self::Api>>>;
}
Loading

0 comments on commit 873d355

Please sign in to comment.