-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
74d0ad9
commit d5c52e5
Showing
11 changed files
with
629 additions
and
483 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
use crate::{ | ||
delegation_proxy::ProxyTrait as _, user_actions::common::MIN_EGLD_TO_DELEGATE, StorageCache, | ||
ERROR_BAD_PAYMENT_AMOUNT, ERROR_NOT_ACTIVE, | ||
}; | ||
|
||
multiversx_sc::imports!(); | ||
|
||
#[multiversx_sc::module] | ||
pub trait AddLiquidityModule: | ||
crate::config::ConfigModule | ||
+ crate::events::EventsModule | ||
+ crate::delegation::DelegationModule | ||
+ crate::liquidity_pool::LiquidityPoolModule | ||
+ multiversx_sc_modules::ongoing_operation::OngoingOperationModule | ||
+ multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule | ||
+ super::common::CommonModule | ||
{ | ||
#[payable("EGLD")] | ||
#[endpoint(addLiquidity)] | ||
fn add_liquidity(&self) { | ||
self.blockchain().check_caller_is_user_account(); | ||
|
||
let storage_cache = StorageCache::new(self); | ||
let caller = self.blockchain().get_caller(); | ||
|
||
let payment = self.call_value().egld_value().clone_value(); | ||
require!( | ||
self.is_state_active(storage_cache.contract_state), | ||
ERROR_NOT_ACTIVE | ||
); | ||
require!(payment >= MIN_EGLD_TO_DELEGATE, ERROR_BAD_PAYMENT_AMOUNT); | ||
|
||
let delegation_contract = self.get_delegation_contract_for_delegate(&payment); | ||
let gas_for_async_call = self.get_gas_for_async_call(); | ||
|
||
self.delegation_proxy_obj() | ||
.contract(delegation_contract.clone()) | ||
.delegate() | ||
.with_gas_limit(gas_for_async_call) | ||
.with_egld_transfer(payment.clone()) | ||
.async_call() | ||
.with_callback(AddLiquidityModule::callbacks(self).add_liquidity_callback( | ||
caller, | ||
delegation_contract, | ||
payment, | ||
)) | ||
.call_and_exit() | ||
} | ||
|
||
#[callback] | ||
fn add_liquidity_callback( | ||
&self, | ||
caller: ManagedAddress, | ||
delegation_contract: ManagedAddress, | ||
staked_tokens: BigUint, | ||
#[call_result] result: ManagedAsyncCallResult<()>, | ||
) { | ||
match result { | ||
ManagedAsyncCallResult::Ok(()) => { | ||
let mut storage_cache = StorageCache::new(self); | ||
self.delegation_contract_data(&delegation_contract) | ||
.update(|contract_data| { | ||
contract_data.total_staked_from_ls_contract += &staked_tokens; | ||
}); | ||
|
||
let ls_token_amount = self.pool_add_liquidity(&staked_tokens, &mut storage_cache); | ||
let user_payment = self.mint_ls_token(ls_token_amount); | ||
self.send().direct_esdt( | ||
&caller, | ||
&user_payment.token_identifier, | ||
user_payment.token_nonce, | ||
&user_payment.amount, | ||
); | ||
|
||
self.emit_add_liquidity_event(&storage_cache, &caller, user_payment.amount); | ||
} | ||
ManagedAsyncCallResult::Err(_) => { | ||
self.send().direct_egld(&caller, &staked_tokens); | ||
self.move_delegation_contract_to_back(delegation_contract); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
use multiversx_sc_modules::ongoing_operation::{ | ||
CONTINUE_OP, DEFAULT_MIN_GAS_TO_SAVE_PROGRESS, STOP_OP, | ||
}; | ||
|
||
use crate::{ | ||
delegation::{ClaimStatus, ClaimStatusType}, | ||
delegation_proxy::ProxyTrait as _, | ||
StorageCache, ERROR_NOT_ACTIVE, ERROR_NO_DELEGATION_CONTRACTS, | ||
}; | ||
|
||
multiversx_sc::imports!(); | ||
|
||
pub const DEFAULT_GAS_TO_CLAIM_REWARDS: u64 = 6_000_000; | ||
|
||
#[multiversx_sc::module] | ||
pub trait ClaimRewardsModule: | ||
crate::config::ConfigModule | ||
+ crate::events::EventsModule | ||
+ crate::delegation::DelegationModule | ||
+ crate::liquidity_pool::LiquidityPoolModule | ||
+ multiversx_sc_modules::ongoing_operation::OngoingOperationModule | ||
+ multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule | ||
+ super::common::CommonModule | ||
{ | ||
#[endpoint(claimRewards)] | ||
fn claim_rewards(&self) { | ||
let storage_cache = StorageCache::new(self); | ||
|
||
require!( | ||
self.is_state_active(storage_cache.contract_state), | ||
ERROR_NOT_ACTIVE | ||
); | ||
|
||
let delegation_addresses_mapper = self.delegation_addresses_list(); | ||
require!( | ||
!delegation_addresses_mapper.is_empty(), | ||
ERROR_NO_DELEGATION_CONTRACTS | ||
); | ||
let claim_status_mapper = self.delegation_claim_status(); | ||
let old_claim_status = claim_status_mapper.get(); | ||
let current_epoch = self.blockchain().get_block_epoch(); | ||
let mut current_claim_status = self.load_operation::<ClaimStatus<Self::Api>>(); | ||
|
||
self.check_claim_operation(¤t_claim_status, old_claim_status, current_epoch); | ||
self.prepare_claim_operation(&mut current_claim_status, current_epoch); | ||
|
||
let run_result = self.run_while_it_has_gas(DEFAULT_MIN_GAS_TO_SAVE_PROGRESS, || { | ||
let delegation_address_node = delegation_addresses_mapper | ||
.get_node_by_id(current_claim_status.current_node) | ||
.unwrap(); | ||
let next_node = delegation_address_node.get_next_node_id(); | ||
let delegation_address = delegation_address_node.into_value(); | ||
|
||
self.delegation_proxy_obj() | ||
.contract(delegation_address) | ||
.claim_rewards() | ||
.with_gas_limit(DEFAULT_GAS_TO_CLAIM_REWARDS) | ||
.transfer_execute(); | ||
|
||
if next_node == 0 { | ||
claim_status_mapper.set(current_claim_status.clone()); | ||
return STOP_OP; | ||
} else { | ||
current_claim_status.current_node = next_node; | ||
} | ||
|
||
CONTINUE_OP | ||
}); | ||
|
||
match run_result { | ||
OperationCompletionStatus::InterruptedBeforeOutOfGas => { | ||
self.save_progress(¤t_claim_status); | ||
} | ||
OperationCompletionStatus::Completed => { | ||
claim_status_mapper.update(|claim_status| { | ||
claim_status.status = ClaimStatusType::Finished; | ||
claim_status.last_claim_block = self.blockchain().get_block_nonce(); | ||
}); | ||
} | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
use crate::{delegation_proxy, StorageCache, ERROR_INSUFFICIENT_GAS}; | ||
|
||
multiversx_sc::imports!(); | ||
|
||
pub const MIN_GAS_FOR_CALLBACK: u64 = 12_000_000; | ||
pub const MIN_GAS_FOR_ASYNC_CALL: u64 = 12_000_000; | ||
pub const MIN_EGLD_TO_DELEGATE: u64 = 1_000_000_000_000_000_000; | ||
|
||
#[multiversx_sc::module] | ||
pub trait CommonModule: | ||
crate::config::ConfigModule | ||
+ crate::liquidity_pool::LiquidityPoolModule | ||
+ multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule | ||
{ | ||
// views | ||
#[view(getLsValueForPosition)] | ||
fn get_ls_value_for_position(&self, ls_token_amount: BigUint) -> BigUint { | ||
let storage_cache = StorageCache::new(self); | ||
self.get_egld_amount(&ls_token_amount, &storage_cache) | ||
} | ||
|
||
fn get_gas_for_async_call(&self) -> u64 { | ||
let gas_left = self.blockchain().get_gas_left(); | ||
require!( | ||
gas_left > MIN_GAS_FOR_ASYNC_CALL + MIN_GAS_FOR_CALLBACK, | ||
ERROR_INSUFFICIENT_GAS | ||
); | ||
|
||
gas_left - MIN_GAS_FOR_CALLBACK | ||
} | ||
|
||
fn send_back_unbond_nft(&self, caller: &ManagedAddress, unstake_token_nonce: u64) { | ||
let unstake_token_id = self.unstake_token().get_token_id(); | ||
self.send().direct_esdt( | ||
caller, | ||
&unstake_token_id, | ||
unstake_token_nonce, | ||
&BigUint::from(1u64), | ||
) | ||
} | ||
|
||
#[proxy] | ||
fn delegation_proxy_obj(&self) -> delegation_proxy::Proxy<Self::Api>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
use crate::{ | ||
delegation::ClaimStatusType, delegation_proxy::ProxyTrait as _, StorageCache, | ||
ERROR_CLAIM_REDELEGATE, ERROR_NOT_ACTIVE, | ||
}; | ||
|
||
multiversx_sc::imports!(); | ||
|
||
#[multiversx_sc::module] | ||
pub trait DelegateRewardsModule: | ||
crate::config::ConfigModule | ||
+ crate::events::EventsModule | ||
+ crate::delegation::DelegationModule | ||
+ crate::liquidity_pool::LiquidityPoolModule | ||
+ multiversx_sc_modules::ongoing_operation::OngoingOperationModule | ||
+ multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule | ||
+ super::common::CommonModule | ||
{ | ||
#[endpoint(delegateRewards)] | ||
fn delegate_rewards(&self) { | ||
let mut storage_cache = StorageCache::new(self); | ||
let claim_status = self.delegation_claim_status().get(); | ||
require!( | ||
self.is_state_active(storage_cache.contract_state), | ||
ERROR_NOT_ACTIVE | ||
); | ||
require!( | ||
claim_status.status == ClaimStatusType::Delegable, | ||
ERROR_CLAIM_REDELEGATE | ||
); | ||
|
||
let rewards_reserve = storage_cache.rewards_reserve.clone(); | ||
storage_cache.rewards_reserve = BigUint::zero(); | ||
let delegation_contract = self.get_delegation_contract_for_delegate(&rewards_reserve); | ||
let gas_for_async_call = self.get_gas_for_async_call(); | ||
|
||
self.delegation_proxy_obj() | ||
.contract(delegation_contract.clone()) | ||
.delegate() | ||
.with_gas_limit(gas_for_async_call) | ||
.with_egld_transfer(rewards_reserve.clone()) | ||
.async_call() | ||
.with_callback( | ||
DelegateRewardsModule::callbacks(self) | ||
.delegate_rewards_callback(delegation_contract, rewards_reserve), | ||
) | ||
.call_and_exit() | ||
} | ||
|
||
#[callback] | ||
fn delegate_rewards_callback( | ||
&self, | ||
delegation_contract: ManagedAddress, | ||
staked_tokens: BigUint, | ||
#[call_result] result: ManagedAsyncCallResult<()>, | ||
) { | ||
let mut storage_cache = StorageCache::new(self); | ||
match result { | ||
ManagedAsyncCallResult::Ok(()) => { | ||
self.delegation_contract_data(&delegation_contract) | ||
.update(|contract_data| { | ||
contract_data.total_staked_from_ls_contract += &staked_tokens; | ||
}); | ||
|
||
self.delegation_claim_status() | ||
.update(|claim_status| claim_status.status = ClaimStatusType::Redelegated); | ||
|
||
storage_cache.virtual_egld_reserve += &staked_tokens; | ||
let sc_address = self.blockchain().get_sc_address(); | ||
self.emit_add_liquidity_event(&storage_cache, &sc_address, BigUint::zero()); | ||
} | ||
ManagedAsyncCallResult::Err(_) => { | ||
storage_cache.rewards_reserve = staked_tokens; | ||
self.move_delegation_contract_to_back(delegation_contract); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
pub mod add_liquidity; | ||
pub mod claim_rewards; | ||
pub mod common; | ||
pub mod delegate_rewards; | ||
pub mod recompute_token_reserve; | ||
pub mod remove_liquidity; | ||
pub mod unbond; |
61 changes: 61 additions & 0 deletions
61
liquid-staking/src/user_actions/recompute_token_reserve.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
use crate::{ | ||
delegation::ClaimStatusType, user_actions::common::MIN_EGLD_TO_DELEGATE, StorageCache, | ||
ERROR_NOT_ACTIVE, ERROR_RECOMPUTE_RESERVES, ERROR_RECOMPUTE_TOO_SOON, | ||
}; | ||
|
||
multiversx_sc::imports!(); | ||
|
||
pub const RECOMPUTE_BLOCK_OFFSET: u64 = 10; | ||
|
||
#[multiversx_sc::module] | ||
pub trait RecomputeTokenReserveModule: | ||
crate::config::ConfigModule | ||
+ crate::events::EventsModule | ||
+ crate::delegation::DelegationModule | ||
+ crate::liquidity_pool::LiquidityPoolModule | ||
+ multiversx_sc_modules::ongoing_operation::OngoingOperationModule | ||
+ multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule | ||
+ super::common::CommonModule | ||
{ | ||
#[endpoint(recomputeTokenReserve)] | ||
fn recompute_token_reserve(&self) { | ||
let mut storage_cache = StorageCache::new(self); | ||
let claim_status_mapper = self.delegation_claim_status(); | ||
let mut claim_status = claim_status_mapper.get(); | ||
|
||
require!( | ||
self.is_state_active(storage_cache.contract_state), | ||
ERROR_NOT_ACTIVE | ||
); | ||
require!( | ||
claim_status.status == ClaimStatusType::Finished, | ||
ERROR_RECOMPUTE_RESERVES | ||
); | ||
|
||
let current_block = self.blockchain().get_block_nonce(); | ||
require!( | ||
current_block >= claim_status.last_claim_block + RECOMPUTE_BLOCK_OFFSET, | ||
ERROR_RECOMPUTE_TOO_SOON | ||
); | ||
|
||
let current_egld_balance = self | ||
.blockchain() | ||
.get_sc_balance(&EgldOrEsdtTokenIdentifier::egld(), 0); | ||
if current_egld_balance | ||
> &storage_cache.total_withdrawn_egld + &claim_status.starting_token_reserve | ||
{ | ||
let rewards = ¤t_egld_balance | ||
- &storage_cache.total_withdrawn_egld | ||
- &claim_status.starting_token_reserve; | ||
storage_cache.rewards_reserve += rewards; | ||
} | ||
|
||
if storage_cache.rewards_reserve >= MIN_EGLD_TO_DELEGATE { | ||
claim_status.status = ClaimStatusType::Delegable; | ||
} else { | ||
claim_status.status = ClaimStatusType::Insufficient; | ||
} | ||
|
||
claim_status_mapper.set(claim_status); | ||
} | ||
} |
Oops, something went wrong.