Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added per block rewards minting #43

Merged
merged 3 commits into from
May 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion elrond_dex_farm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const EXIT_FARM_NO_PENALTY_MIN_EPOCHS: u64 = 3;

pub mod liquidity_pool;
pub use crate::liquidity_pool::*;
pub mod rewards;
pub use crate::rewards::*;

#[derive(TopEncode, TopDecode, TypeAbi)]
pub struct FarmTokenAttributes<BigUint: BigUintApi> {
Expand Down Expand Up @@ -53,6 +55,9 @@ pub trait Farm {
#[module(LiquidityPoolModuleImpl)]
fn liquidity_pool(&self) -> LiquidityPoolModuleImpl<T, BigInt, BigUint>;

#[module(RewardsModule)]
fn rewards(&self) -> RewardsModule<T, BigInt, BigUint>;

#[init]
fn init(
&self,
Expand Down Expand Up @@ -258,6 +263,7 @@ pub trait Farm {
self.burn(&payment_token_id, token_nonce, &liquidity);

let caller = self.blockchain().get_caller();
self.rewards().mint_rewards(&farming_pool_token_id);
self.send_reward_and_farmed_tokens(
reward,
farming_pool_token_id,
Expand Down Expand Up @@ -355,7 +361,7 @@ pub trait Farm {
return Ok(initial_worth);
}

let reward = sc_try!(self.liquidity_pool().calculate_reward(
let reward = sc_try!(self.rewards().calculate_reward_for_given_liquidity(
liquidity,
initial_worth,
self.farming_pool_token_id().get(),
Expand Down Expand Up @@ -544,6 +550,7 @@ pub trait Farm {
) -> SCResult<SftTokenAmountPair<BigUint>> {
let farm_contribution = sc_try!(self.get_farm_contribution(&token_in, &amount_in));
let farming_pool_token_id = self.farming_pool_token_id().get();

let liquidity = self.liquidity_pool().calculate_liquidity(
&farm_contribution,
&farming_pool_token_id,
Expand Down
49 changes: 9 additions & 40 deletions elrond_dex_farm/src/liquidity_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ elrond_wasm::derive_imports!();

const MINIMUM_INITIAL_FARM_AMOUNT: u64 = 1000;

pub use crate::rewards::*;

#[elrond_wasm_derive::module(LiquidityPoolModuleImpl)]
pub trait LiquidityPoolModule {
#[module(RewardsModule)]
fn rewards(&self) -> RewardsModule<T, BigInt, BigUint>;

fn add_liquidity(
&self,
amount: BigUint,
Expand Down Expand Up @@ -46,7 +51,7 @@ pub trait LiquidityPoolModule {
farming_pool_token_id: TokenIdentifier,
farmed_token_id: TokenIdentifier,
) -> SCResult<BigUint> {
let reward = sc_try!(self.calculate_reward(
let reward = sc_try!(self.rewards().calculate_reward_for_given_liquidity(
liquidity.clone(),
initial_worth.clone(),
farming_pool_token_id.clone()
Expand Down Expand Up @@ -80,6 +85,8 @@ pub trait LiquidityPoolModule {
farming_pool_token_id.as_esdt_identifier(),
0,
);
let reward_amount = self.rewards().calculate_reward_amount_current_block();

if !is_virtual_amount {
actual_reserves -= amount.clone();
}
Expand All @@ -88,49 +95,11 @@ pub trait LiquidityPoolModule {
let minimum_amount = BigUint::from(MINIMUM_INITIAL_FARM_AMOUNT);
amount - &minimum_amount
} else {
let total_reserves = virtual_reserves + actual_reserves;
let total_reserves = virtual_reserves + actual_reserves + reward_amount;
amount * &total_supply / total_reserves
}
}

fn calculate_reward(
&self,
liquidity: BigUint,
initial_worth: BigUint,
token_id: TokenIdentifier,
) -> SCResult<BigUint> {
require!(liquidity > 0, "Liquidity needs to be greater than 0");

let total_supply = self.total_supply().get();
require!(
total_supply > liquidity,
"Removing more liquidity than existent"
);

let virtual_reserves = self.virtual_reserves().get();
require!(
virtual_reserves > initial_worth,
"Removing more virtual reserve than existent"
);

let actual_reserves = self.blockchain().get_esdt_balance(
&self.blockchain().get_sc_address(),
token_id.as_esdt_identifier(),
0,
);

let total_reserves = virtual_reserves + actual_reserves;
let worth = liquidity * total_reserves / total_supply;

let reward = if worth > initial_worth {
worth - initial_worth
} else {
BigUint::zero()
};

Ok(reward)
}

#[view(getTotalSupply)]
#[storage_mapper("total_supply")]
fn total_supply(&self) -> SingleValueMapper<Self::Storage, BigUint>;
Expand Down
98 changes: 98 additions & 0 deletions elrond_dex_farm/src/rewards.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use elrond_wasm::only_owner;

elrond_wasm::imports!();
elrond_wasm::derive_imports!();

type Nonce = u64;

pub use crate::liquidity_pool::*;

#[elrond_wasm_derive::module(RewardsModule)]
pub trait RewardsModuleImpl {
#[module(LiquidityPoolModuleImpl)]
fn liquidity_pool(&self) -> LiquidityPoolModuleImpl<T, BigInt, BigUint>;

#[endpoint(setPerBlockRewardAmount)]
fn start_produce_per_block_rewards(&self, per_block_amount: u64) -> SCResult<()> {
only_owner!(self, "Permission denied");
self.per_block_reward_amount().set(&per_block_amount);
self.last_reward_block_nonce()
.set(&self.blockchain().get_block_nonce());
Ok(())
}

fn calculate_reward_amount_current_block(&self) -> BigUint {
let current_nonce = self.blockchain().get_block_nonce();
self.calculate_reward_amount(current_nonce)
}

fn calculate_reward_amount(&self, block_nonce: Nonce) -> BigUint {
let last_reward_nonce = self.last_reward_block_nonce().get();
let per_block_reward = self.per_block_reward_amount().get();
if block_nonce > last_reward_nonce && per_block_reward > 0 {
BigUint::from(per_block_reward) * BigUint::from(block_nonce - last_reward_nonce)
} else {
BigUint::zero()
}
}

fn mint_rewards(&self, token_id: &TokenIdentifier) {
let current_nonce = self.blockchain().get_block_nonce();
let to_mint = self.calculate_reward_amount(current_nonce);
if to_mint != 0 {
self.send().esdt_local_mint(
self.blockchain().get_gas_left(),
token_id.as_esdt_identifier(),
&to_mint,
);
self.last_reward_block_nonce().set(&current_nonce);
}
}

fn calculate_reward_for_given_liquidity(
&self,
liquidity: BigUint,
initial_worth: BigUint,
token_id: TokenIdentifier,
) -> SCResult<BigUint> {
require!(liquidity > 0, "Liquidity needs to be greater than 0");

let total_supply = self.liquidity_pool().total_supply().get();
require!(
total_supply > liquidity,
"Removing more liquidity than existent"
);

let virtual_reserves = self.liquidity_pool().virtual_reserves().get();
require!(
virtual_reserves > initial_worth,
"Removing more virtual reserve than existent"
);

let actual_reserves = self.blockchain().get_esdt_balance(
&self.blockchain().get_sc_address(),
token_id.as_esdt_identifier(),
0,
);
let reward_amount = self.calculate_reward_amount_current_block();

let total_reserves = virtual_reserves + actual_reserves + reward_amount;
let worth = liquidity * total_reserves / total_supply;

let reward = if worth > initial_worth {
worth - initial_worth
} else {
BigUint::zero()
};

Ok(reward)
}

#[view(getLastRewardEpoch)]
#[storage_mapper("last_reward_block_nonce")]
fn last_reward_block_nonce(&self) -> SingleValueMapper<Self::Storage, Nonce>;

#[view(getPerBlockRewardAmount)]
#[storage_mapper("per_block_reward_amount")]
fn per_block_reward_amount(&self) -> SingleValueMapper<Self::Storage, u64>;
}