From 8d54617525d3618d68290992a7c7376bdd625983 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 14 Oct 2022 11:45:10 +0200 Subject: [PATCH 01/36] Added farming contract --- Cargo.toml | 4 ++- farming/contracts/farming/Cargo.toml | 41 ++++++++++++++++++++++++++++ farming/contracts/farming/lib.rs | 27 ++++++++++++++++++ farming/logics/Cargo.toml | 40 +++++++++++++++++++++++++++ farming/logics/lib.rs | 4 +++ farming/logics/traits/farming.rs | 21 ++++++++++++++ farming/logics/traits/mod.rs | 1 + 7 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 farming/contracts/farming/Cargo.toml create mode 100644 farming/contracts/farming/lib.rs create mode 100644 farming/logics/Cargo.toml create mode 100644 farming/logics/lib.rs create mode 100644 farming/logics/traits/farming.rs create mode 100644 farming/logics/traits/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 6cf78d8..edb2791 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,10 @@ [workspace] members = [ "uniswap-v2/contracts/**", + "farming/contracts/**", ] exclude = [ - "uniswap-v2/logics" + "uniswap-v2/logics", + "farming/logics" ] diff --git a/farming/contracts/farming/Cargo.toml b/farming/contracts/farming/Cargo.toml new file mode 100644 index 0000000..6a93976 --- /dev/null +++ b/farming/contracts/farming/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "farming_contract" +version = "0.1.0" +authors = ["Stake Technologies "] +edition = "2021" + +[dependencies] +ink_primitives = { version = "~3.3.0", default-features = false } +ink_metadata = { version = "~3.3.0", default-features = false, features = ["derive"], optional = true } +ink_env = { version = "~3.3.0", default-features = false } +ink_storage = { version = "~3.3.0", default-features = false } +ink_lang = { version = "~3.3.0", default-features = false } +ink_prelude = { version = "~3.3.0", default-features = false } + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } + +openbrush = { version = "2.2.0", default-features = false } +farming = { path = "../../logics", default-features = false } + +[lib] +name = "farming_contract" +path = "lib.rs" +crate-type = ["cdylib"] + +[features] +default = ["std"] +std = [ + "ink_primitives/std", + "ink_metadata", + "ink_metadata/std", + "ink_env/std", + "ink_storage/std", + "ink_lang/std", + "scale/std", + "scale-info", + "scale-info/std", + "openbrush/std", + "farming/std" +] +ink-as-dependency = [] diff --git a/farming/contracts/farming/lib.rs b/farming/contracts/farming/lib.rs new file mode 100644 index 0000000..5cdea60 --- /dev/null +++ b/farming/contracts/farming/lib.rs @@ -0,0 +1,27 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![feature(min_specialization)] + +#[openbrush::contract] +pub mod farming { + use farming::traits::farming::*; + use ink_storage::traits::SpreadAllocate; + use openbrush::traits::Storage; + + #[ink(storage)] + #[derive(Default, SpreadAllocate, Storage)] + pub struct FarmingContract { + #[storage_field] + farming: Data, + } + + impl Farming for FarmingContract {} + + impl FarmingContract { + #[ink(constructor)] + pub fn new(arsw_token: AccountId) -> Self { + ink_lang::codegen::initialize_contract(|instance: &mut Self| { + instance.farming.arsw_token = arsw_token; + }) + } + } +} diff --git a/farming/logics/Cargo.toml b/farming/logics/Cargo.toml new file mode 100644 index 0000000..62306ba --- /dev/null +++ b/farming/logics/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "farming" +version = "0.1.0" +authors = ["Stake Technologies "] +edition = "2021" + +[dependencies] +ink_primitives = { version = "~3.3.0", default-features = false } +ink_metadata = { version = "~3.3.0", default-features = false, features = ["derive"], optional = true } +ink_env = { version = "~3.3.0", default-features = false } +ink_storage = { version = "~3.3.0", default-features = false } +ink_lang = { version = "~3.3.0", default-features = false } +ink_prelude = { version = "~3.3.0", default-features = false } + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } + +openbrush = { version = "2.2.0", default-features = false } + +[lib] +name = "farming" +path = "lib.rs" +crate-type = [ + "rlib", +] + +[features] +default = ["std"] +std = [ + "ink_primitives/std", + "ink_metadata", + "ink_metadata/std", + "ink_env/std", + "ink_storage/std", + "ink_lang/std", + "scale/std", + "scale-info", + "scale-info/std", + "openbrush/std", +] diff --git a/farming/logics/lib.rs b/farming/logics/lib.rs new file mode 100644 index 0000000..1b54fff --- /dev/null +++ b/farming/logics/lib.rs @@ -0,0 +1,4 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![feature(min_specialization)] + +pub mod traits; diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs new file mode 100644 index 0000000..830fcd8 --- /dev/null +++ b/farming/logics/traits/farming.rs @@ -0,0 +1,21 @@ +use openbrush::traits::{ + AccountId, + Balance, + Timestamp, +}; + +pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data); + +#[derive(Default, Debug)] +#[openbrush::upgradeable_storage(STORAGE_KEY)] +pub struct Data { + pub arsw_token: AccountId, +} + +#[openbrush::trait_definition] +pub trait Farming { + #[ink(message)] + fn add(&self) -> u32 { + 10u32 + } +} diff --git a/farming/logics/traits/mod.rs b/farming/logics/traits/mod.rs new file mode 100644 index 0000000..9113d80 --- /dev/null +++ b/farming/logics/traits/mod.rs @@ -0,0 +1 @@ +pub mod farming; From 95f296bc43319b4c03d150e080c726eb7bfb741b Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 14 Oct 2022 15:07:24 +0200 Subject: [PATCH 02/36] Added storage + events --- farming/logics/traits/farming.rs | 105 +++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 4 deletions(-) diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index 830fcd8..fdcbfd5 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -1,7 +1,10 @@ -use openbrush::traits::{ - AccountId, - Balance, - Timestamp, +use ink_prelude::vec::Vec; +use openbrush::{ + storage::Mapping, + traits::{ + AccountId, + Balance, + }, }; pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data); @@ -9,13 +12,107 @@ pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data); #[derive(Default, Debug)] #[openbrush::upgradeable_storage(STORAGE_KEY)] pub struct Data { + /// Address of ARSW contract. pub arsw_token: AccountId, + + /// Info of each MasterChef user. + /// u128 `amount` LP token amount the user has provided. + /// u128 `reward_debt` The amount of ARSW entitled to the user. + /// key is (u32 `pool_id`, AccountId `user_address` ) + pub user_info: Mapping<(u32, AccountId), (u128, i128)>, + + /// Info of each MasterChef pool. + /// u64 `alloc_point` The amount of allocation points assigned to the pool. + /// Also known as the amount of ARSW to distribute per block. + /// key is u32 `pool_id` + pub pool_info: Mapping, + pub next_pool_info_id: u32, + + /// Address of the LP token for each MasterChef pool. + pub lp_tokens: Vec, + + /// Address of each `rewarder` contract in MasterChef. + pub rewarders: Vec, + + /// Total allocation points. Must be the sum of all allocation points in all pools. + pub total_alloc_point: u32, } +pub const ACC_ARSW_PRECISION: u8 = 12; +pub const ARTHSWAP_ORIGIN_BLOCK: u32 = 1u32; +pub const BLOCK_PER_PERIOD: u32 = 215000u32; +pub const MAX_PERIOD: u8 = 23u8; +pub const FIRST_PERIOD_REWERD_SUPPLY: Balance = 151629858171523000000u128; + #[openbrush::trait_definition] pub trait Farming { #[ink(message)] fn add(&self) -> u32 { 10u32 } + + fn _emit_deposit_event( + &self, + _user: AccountId, + _pool_id: u32, + _amount: Balance, + _to: AccountId, + ) { + } + + fn _emit_withdraw_event( + &self, + _user: AccountId, + _pool_id: u32, + _amount: Balance, + _to: AccountId, + ) { + } + + fn _emit_emergency_withdraw_event( + &self, + _user: AccountId, + _pool_id: u32, + _amount: Balance, + _to: AccountId, + ) { + } + + fn _emit_harvest_event( + &self, + _user: AccountId, + _pool_id: u32, + _amount: Balance, + _to: AccountId, + ) { + } + + fn _emit_log_pool_addition_event( + &self, + _pool_id: u32, + _alloc_point: u128, + _lp_token: AccountId, + _rewarder: AccountId, + ) { + } + + fn _emit_log_set_pool_event( + &self, + _pool_id: u32, + _alloc_point: u128, + _rewardes: AccountId, + _overwrite: bool, + ) { + } + + fn _emit_log_update_pool_event( + &self, + _pool_id: u32, + _last_reward_block: u32, + _lp_supply: Balance, + _acc_arsw_per_share: Balance, + ) { + } + + fn _emit_deposit_arsw_event(&self, _block_number: u32, _amount: Balance) {} } From 3245faf740bf746712ac82e25f531fea99638867 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 14 Oct 2022 15:45:36 +0200 Subject: [PATCH 03/36] separated Traits --- farming/contracts/farming/lib.rs | 10 ++- farming/logics/traits/data.rs | 36 +++++++++ farming/logics/traits/events.rs | 72 ++++++++++++++++++ farming/logics/traits/farming.rs | 124 +++++-------------------------- farming/logics/traits/getters.rs | 10 +++ farming/logics/traits/mod.rs | 3 + 6 files changed, 149 insertions(+), 106 deletions(-) create mode 100644 farming/logics/traits/data.rs create mode 100644 farming/logics/traits/events.rs create mode 100644 farming/logics/traits/getters.rs diff --git a/farming/contracts/farming/lib.rs b/farming/contracts/farming/lib.rs index 5cdea60..70e9281 100644 --- a/farming/contracts/farming/lib.rs +++ b/farming/contracts/farming/lib.rs @@ -3,7 +3,11 @@ #[openbrush::contract] pub mod farming { - use farming::traits::farming::*; + use farming::traits::{ + events::*, + farming::*, + getters::*, + }; use ink_storage::traits::SpreadAllocate; use openbrush::traits::Storage; @@ -16,6 +20,10 @@ pub mod farming { impl Farming for FarmingContract {} + impl FarmingGetters for FarmingContract {} + + impl FarmingEvents for FarmingContract {} + impl FarmingContract { #[ink(constructor)] pub fn new(arsw_token: AccountId) -> Self { diff --git a/farming/logics/traits/data.rs b/farming/logics/traits/data.rs new file mode 100644 index 0000000..079a9a1 --- /dev/null +++ b/farming/logics/traits/data.rs @@ -0,0 +1,36 @@ +use ink_prelude::vec::Vec; +use openbrush::{ + storage::Mapping, + traits::AccountId, +}; + +pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data); + +#[derive(Default, Debug)] +#[openbrush::upgradeable_storage(STORAGE_KEY)] +pub struct Data { + /// Address of ARSW contract. + pub arsw_token: AccountId, + + /// Info of each MasterChef user. + /// u128 `amount` LP token amount the user has provided. + /// u128 `reward_debt` The amount of ARSW entitled to the user. + /// key is (u32 `pool_id`, AccountId `user_address` ) + pub user_info: Mapping<(u32, AccountId), (u128, i128)>, + + /// Info of each MasterChef pool. + /// u64 `alloc_point` The amount of allocation points assigned to the pool. + /// Also known as the amount of ARSW to distribute per block. + /// key is u32 `pool_id` + pub pool_info: Mapping, + pub pool_info_length: u32, + + /// Address of the LP token for each MasterChef pool. + pub lp_tokens: Vec, + + /// Address of each `rewarder` contract in MasterChef. + pub rewarders: Vec, + + /// Total allocation points. Must be the sum of all allocation points in all pools. + pub total_alloc_point: u32, +} diff --git a/farming/logics/traits/events.rs b/farming/logics/traits/events.rs new file mode 100644 index 0000000..91864f4 --- /dev/null +++ b/farming/logics/traits/events.rs @@ -0,0 +1,72 @@ +use openbrush::traits::{ + AccountId, + Balance, +}; + +#[openbrush::trait_definition] +pub trait FarmingEvents { + fn _emit_deposit_event( + &self, + _user: AccountId, + _pool_id: u32, + _amount: Balance, + _to: AccountId, + ) { + } + + fn _emit_withdraw_event( + &self, + _user: AccountId, + _pool_id: u32, + _amount: Balance, + _to: AccountId, + ) { + } + + fn _emit_emergency_withdraw_event( + &self, + _user: AccountId, + _pool_id: u32, + _amount: Balance, + _to: AccountId, + ) { + } + + fn _emit_harvest_event( + &self, + _user: AccountId, + _pool_id: u32, + _amount: Balance, + _to: AccountId, + ) { + } + + fn _emit_log_pool_addition_event( + &self, + _pool_id: u32, + _alloc_point: u128, + _lp_token: AccountId, + _rewarder: AccountId, + ) { + } + + fn _emit_log_set_pool_event( + &self, + _pool_id: u32, + _alloc_point: u128, + _rewardes: AccountId, + _overwrite: bool, + ) { + } + + fn _emit_log_update_pool_event( + &self, + _pool_id: u32, + _last_reward_block: u32, + _lp_supply: Balance, + _acc_arsw_per_share: Balance, + ) { + } + + fn _emit_deposit_arsw_event(&self, _block_number: u32, _amount: Balance) {} +} diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index fdcbfd5..cd9a064 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -1,43 +1,10 @@ -use ink_prelude::vec::Vec; -use openbrush::{ - storage::Mapping, - traits::{ - AccountId, - Balance, - }, +pub use crate::traits::data::Data; +use openbrush::traits::{ + AccountId, + Balance, + Storage, }; -pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data); - -#[derive(Default, Debug)] -#[openbrush::upgradeable_storage(STORAGE_KEY)] -pub struct Data { - /// Address of ARSW contract. - pub arsw_token: AccountId, - - /// Info of each MasterChef user. - /// u128 `amount` LP token amount the user has provided. - /// u128 `reward_debt` The amount of ARSW entitled to the user. - /// key is (u32 `pool_id`, AccountId `user_address` ) - pub user_info: Mapping<(u32, AccountId), (u128, i128)>, - - /// Info of each MasterChef pool. - /// u64 `alloc_point` The amount of allocation points assigned to the pool. - /// Also known as the amount of ARSW to distribute per block. - /// key is u32 `pool_id` - pub pool_info: Mapping, - pub next_pool_info_id: u32, - - /// Address of the LP token for each MasterChef pool. - pub lp_tokens: Vec, - - /// Address of each `rewarder` contract in MasterChef. - pub rewarders: Vec, - - /// Total allocation points. Must be the sum of all allocation points in all pools. - pub total_alloc_point: u32, -} - pub const ACC_ARSW_PRECISION: u8 = 12; pub const ARTHSWAP_ORIGIN_BLOCK: u32 = 1u32; pub const BLOCK_PER_PERIOD: u32 = 215000u32; @@ -45,74 +12,21 @@ pub const MAX_PERIOD: u8 = 23u8; pub const FIRST_PERIOD_REWERD_SUPPLY: Balance = 151629858171523000000u128; #[openbrush::trait_definition] -pub trait Farming { +pub trait Farming: Storage { #[ink(message)] - fn add(&self) -> u32 { - 10u32 - } - - fn _emit_deposit_event( - &self, - _user: AccountId, - _pool_id: u32, - _amount: Balance, - _to: AccountId, - ) { - } - - fn _emit_withdraw_event( - &self, - _user: AccountId, - _pool_id: u32, - _amount: Balance, - _to: AccountId, - ) { - } - - fn _emit_emergency_withdraw_event( - &self, - _user: AccountId, - _pool_id: u32, - _amount: Balance, - _to: AccountId, - ) { - } - - fn _emit_harvest_event( - &self, - _user: AccountId, - _pool_id: u32, - _amount: Balance, - _to: AccountId, - ) { - } - - fn _emit_log_pool_addition_event( - &self, - _pool_id: u32, - _alloc_point: u128, - _lp_token: AccountId, - _rewarder: AccountId, - ) { - } - - fn _emit_log_set_pool_event( - &self, - _pool_id: u32, - _alloc_point: u128, - _rewardes: AccountId, - _overwrite: bool, - ) { - } - - fn _emit_log_update_pool_event( - &self, - _pool_id: u32, - _last_reward_block: u32, - _lp_supply: Balance, - _acc_arsw_per_share: Balance, - ) { + fn check_pool_duplicate(&self, lp_token: AccountId) -> Result<(), FarmingError> { + let lp_tokens = &self.data::().lp_tokens; + for i in 0..lp_tokens.len() { + if lp_tokens[i] == lp_token { + return Err(FarmingError::DuplicateLPToken) + } + } + Ok(()) } +} - fn _emit_deposit_arsw_event(&self, _block_number: u32, _amount: Balance) {} +#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] +pub enum FarmingError { + DuplicateLPToken, } diff --git a/farming/logics/traits/getters.rs b/farming/logics/traits/getters.rs new file mode 100644 index 0000000..08b1072 --- /dev/null +++ b/farming/logics/traits/getters.rs @@ -0,0 +1,10 @@ +use crate::traits::farming::Data; +use openbrush::traits::Storage; + +#[openbrush::trait_definition] +pub trait FarmingGetters: Storage { + #[ink(message)] + fn pool_length(&self) -> u32 { + self.data::().pool_info_length + } +} diff --git a/farming/logics/traits/mod.rs b/farming/logics/traits/mod.rs index 9113d80..321934a 100644 --- a/farming/logics/traits/mod.rs +++ b/farming/logics/traits/mod.rs @@ -1 +1,4 @@ +pub mod data; +pub mod events; pub mod farming; +pub mod getters; From aa90d40224d549f7ea8f32355ef524d0d38caf19 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 14 Oct 2022 16:49:08 +0200 Subject: [PATCH 04/36] Added Ownable + add --- farming/contracts/farming/Cargo.toml | 2 +- farming/contracts/farming/lib.rs | 12 ++++++- farming/logics/Cargo.toml | 2 +- farming/logics/traits/farming.rs | 52 ++++++++++++++++++++++++---- 4 files changed, 58 insertions(+), 10 deletions(-) diff --git a/farming/contracts/farming/Cargo.toml b/farming/contracts/farming/Cargo.toml index 6a93976..2f3d162 100644 --- a/farming/contracts/farming/Cargo.toml +++ b/farming/contracts/farming/Cargo.toml @@ -15,7 +15,7 @@ ink_prelude = { version = "~3.3.0", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } -openbrush = { version = "2.2.0", default-features = false } +openbrush = { version = "2.2.0", default-features = false, features = ["ownable"] } farming = { path = "../../logics", default-features = false } [lib] diff --git a/farming/contracts/farming/lib.rs b/farming/contracts/farming/lib.rs index 70e9281..0436cf7 100644 --- a/farming/contracts/farming/lib.rs +++ b/farming/contracts/farming/lib.rs @@ -9,13 +9,21 @@ pub mod farming { getters::*, }; use ink_storage::traits::SpreadAllocate; - use openbrush::traits::Storage; + use openbrush::{ + contracts::{ + ownable, + ownable::Internal, + }, + traits::Storage, + }; #[ink(storage)] #[derive(Default, SpreadAllocate, Storage)] pub struct FarmingContract { #[storage_field] farming: Data, + #[storage_field] + ownable: ownable::Data, } impl Farming for FarmingContract {} @@ -28,6 +36,8 @@ pub mod farming { #[ink(constructor)] pub fn new(arsw_token: AccountId) -> Self { ink_lang::codegen::initialize_contract(|instance: &mut Self| { + let caller = instance.env().caller(); + instance._init_with_owner(caller); instance.farming.arsw_token = arsw_token; }) } diff --git a/farming/logics/Cargo.toml b/farming/logics/Cargo.toml index 62306ba..7f1eeaf 100644 --- a/farming/logics/Cargo.toml +++ b/farming/logics/Cargo.toml @@ -15,7 +15,7 @@ ink_prelude = { version = "~3.3.0", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } -openbrush = { version = "2.2.0", default-features = false } +openbrush = { version = "2.2.0", default-features = false, features = ["ownable"] } [lib] name = "farming" diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index cd9a064..8dc8fa5 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -1,8 +1,15 @@ -pub use crate::traits::data::Data; -use openbrush::traits::{ - AccountId, - Balance, - Storage, +pub use crate::traits::{ + data::Data, + getters::FarmingGetters, +}; +use openbrush::{ + contracts::ownable::*, + modifiers, + traits::{ + AccountId, + Balance, + Storage, + }, }; pub const ACC_ARSW_PRECISION: u8 = 12; @@ -12,9 +19,21 @@ pub const MAX_PERIOD: u8 = 23u8; pub const FIRST_PERIOD_REWERD_SUPPLY: Balance = 151629858171523000000u128; #[openbrush::trait_definition] -pub trait Farming: Storage { +pub trait Farming: Storage + Storage + FarmingGetters { #[ink(message)] - fn check_pool_duplicate(&self, lp_token: AccountId) -> Result<(), FarmingError> { + #[modifiers(only_owner)] + fn add( + &mut self, + alloc_point: u128, + lp_token: AccountId, + rewarder: AccountId, + ) -> Result<(), FarmingError> { + self._check_pool_duplicate(lp_token)?; + self._update_all_pools()?; + Ok(()) + } + + fn _check_pool_duplicate(&self, lp_token: AccountId) -> Result<(), FarmingError> { let lp_tokens = &self.data::().lp_tokens; for i in 0..lp_tokens.len() { if lp_tokens[i] == lp_token { @@ -23,10 +42,29 @@ pub trait Farming: Storage { } Ok(()) } + + fn _update_all_pools(&mut self) -> Result<(), FarmingError> { + let lp_tokens = &self.data::().lp_tokens; + for i in 0..lp_tokens.len() { + self._update_pool(i as u32)?; + } + Ok(()) + } + + fn _update_pool(&mut self, pool_id: u32) -> Result<(), FarmingError> { + Ok(()) + } } #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] pub enum FarmingError { + OwnableError(OwnableError), DuplicateLPToken, } + +impl From for FarmingError { + fn from(error: OwnableError) -> Self { + FarmingError::OwnableError(error) + } +} From 2d05454434a040e92f59a7eee5045bcea030ac0f Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Mon, 17 Oct 2022 17:50:31 +0200 Subject: [PATCH 05/36] update pool + storage refacto --- farming/logics/traits/data.rs | 36 ++++++++++++++----- farming/logics/traits/farming.rs | 61 ++++++++++++++++++++++++++++---- farming/logics/traits/getters.rs | 16 ++++++++- 3 files changed, 97 insertions(+), 16 deletions(-) diff --git a/farming/logics/traits/data.rs b/farming/logics/traits/data.rs index 079a9a1..d9212d0 100644 --- a/farming/logics/traits/data.rs +++ b/farming/logics/traits/data.rs @@ -1,11 +1,27 @@ use ink_prelude::vec::Vec; -use openbrush::{ - storage::Mapping, - traits::AccountId, +use ink_storage::{ + traits::*, + Mapping, +}; +use openbrush::traits::AccountId; +use scale::{ + Decode, + Encode, }; pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data); +#[derive(Encode, Decode, SpreadLayout, PackedLayout, SpreadAllocate, Default)] +#[cfg_attr( + feature = "std", + derive(Debug, PartialEq, Eq, scale_info::TypeInfo, StorageLayout) +)] +pub struct Pool { + pub acc_arsw_per_share: u128, + pub last_reward_block: u32, + pub alloc_point: u64, +} + #[derive(Default, Debug)] #[openbrush::upgradeable_storage(STORAGE_KEY)] pub struct Data { @@ -13,16 +29,18 @@ pub struct Data { pub arsw_token: AccountId, /// Info of each MasterChef user. - /// u128 `amount` LP token amount the user has provided. - /// u128 `reward_debt` The amount of ARSW entitled to the user. - /// key is (u32 `pool_id`, AccountId `user_address` ) + /// key (`pool_id`: u32, `user_address`: AccountId ) + /// Value (`amount`: u128, `reward_debt`: u128) + /// `amount` LP token amount the user has provided. + /// `reward_debt` The amount of ARSW entitled to the user. pub user_info: Mapping<(u32, AccountId), (u128, i128)>, /// Info of each MasterChef pool. - /// u64 `alloc_point` The amount of allocation points assigned to the pool. + /// Key `pool_id`: u32 + /// Value Pool (`acc_arsw_per_share`: u128, `last_reward_block`: u32, `alloc_point`: u64 ) + /// `alloc_point` The amount of allocation points assigned to the pool. /// Also known as the amount of ARSW to distribute per block. - /// key is u32 `pool_id` - pub pool_info: Mapping, + pub pool_info: Mapping, pub pool_info_length: u32, /// Address of the LP token for each MasterChef pool. diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index 8dc8fa5..865c0df 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -1,9 +1,15 @@ pub use crate::traits::{ - data::Data, + data::{ + Data, + Pool, + }, getters::FarmingGetters, }; use openbrush::{ - contracts::ownable::*, + contracts::{ + ownable::*, + traits::psp22::PSP22Ref, + }, modifiers, traits::{ AccountId, @@ -35,10 +41,8 @@ pub trait Farming: Storage + Storage + FarmingGetters { fn _check_pool_duplicate(&self, lp_token: AccountId) -> Result<(), FarmingError> { let lp_tokens = &self.data::().lp_tokens; - for i in 0..lp_tokens.len() { - if lp_tokens[i] == lp_token { - return Err(FarmingError::DuplicateLPToken) - } + if lp_tokens.iter().any(|lp| *lp == lp_token) { + return Err(FarmingError::DuplicateLPToken) } Ok(()) } @@ -52,8 +56,48 @@ pub trait Farming: Storage + Storage + FarmingGetters { } fn _update_pool(&mut self, pool_id: u32) -> Result<(), FarmingError> { + let pool = self + .get_pool_infos(pool_id) + .ok_or(FarmingError::PoolNotFound)?; + let current_block = Self::env().block_number(); + if current_block > pool.last_reward_block { + let lp_token = self + .get_lp_token(pool_id) + .ok_or(FarmingError::LpTokenNotFound)?; + let lp_supply = PSP22Ref::balance_of(&lp_token, Self::env().account_id()); + if lp_supply > 0 { + let additional_acc_arsw_per_share = + self._calculate_additional_acc_arsw_per_share(pool, current_block, lp_supply)?; + } + } Ok(()) } + + fn _calculate_additional_acc_arsw_per_share( + &mut self, + pool_info: Pool, + current_block: u32, + lp_supply: Balance, + ) -> Result { + if lp_supply == 0 { + return Err(FarmingError::LpSupplyIsZero) + } + let last_reward_block_period = self._get_period(pool_info.last_reward_block)?; + let current_period = self._get_period(Self::env().block_number())?; + Ok(10u128) + } + + fn _get_period(&self, block_number: u32) -> Result { + if block_number < ARTHSWAP_ORIGIN_BLOCK { + return Err(FarmingError::BlockNumberLowerThanOriginBlock) + } + + // BLOCK_PER_PERIOD is never 0 + return Ok(block_number + .checked_sub(ARTHSWAP_ORIGIN_BLOCK) + .ok_or(FarmingError::SubUnderflow1)? + / BLOCK_PER_PERIOD) + } } #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] @@ -61,6 +105,11 @@ pub trait Farming: Storage + Storage + FarmingGetters { pub enum FarmingError { OwnableError(OwnableError), DuplicateLPToken, + PoolNotFound, + LpTokenNotFound, + LpSupplyIsZero, + BlockNumberLowerThanOriginBlock, + SubUnderflow1, } impl From for FarmingError { diff --git a/farming/logics/traits/getters.rs b/farming/logics/traits/getters.rs index 08b1072..0615b83 100644 --- a/farming/logics/traits/getters.rs +++ b/farming/logics/traits/getters.rs @@ -1,4 +1,8 @@ -use crate::traits::farming::Data; +use crate::traits::{ + data::Pool, + farming::Data, +}; +use ink_env::AccountId; use openbrush::traits::Storage; #[openbrush::trait_definition] @@ -7,4 +11,14 @@ pub trait FarmingGetters: Storage { fn pool_length(&self) -> u32 { self.data::().pool_info_length } + + #[ink(message)] + fn get_pool_infos(&self, pool_id: u32) -> Option { + self.data::().pool_info.get(&pool_id) + } + + #[ink(message)] + fn get_lp_token(&self, pool_id: u32) -> Option { + self.data::().lp_tokens.get(pool_id as usize).copied() + } } From b286a1c62879d7ba9bcc2947682a506d04322400 Mon Sep 17 00:00:00 2001 From: Hyunggyu Jang Date: Tue, 18 Oct 2022 17:39:52 +0900 Subject: [PATCH 06/36] Provide tentative stake/unstake features --- farming/logics/traits/farming.rs | 99 +++++++++++++++++++++++++++++++- farming/logics/traits/getters.rs | 5 ++ 2 files changed, 101 insertions(+), 3 deletions(-) diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index 865c0df..e32e9fa 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -5,10 +5,14 @@ pub use crate::traits::{ }, getters::FarmingGetters, }; +use ink_prelude::vec::Vec; use openbrush::{ contracts::{ ownable::*, - traits::psp22::PSP22Ref, + traits::psp22::{ + PSP22Error, + PSP22Ref, + }, }, modifiers, traits::{ @@ -36,6 +40,82 @@ pub trait Farming: Storage + Storage + FarmingGetters { ) -> Result<(), FarmingError> { self._check_pool_duplicate(lp_token)?; self._update_all_pools()?; + self.data::().pool_info_length += 1; + self.data::().lp_tokens.push(lp_token); + Ok(()) + } + + #[ink(message)] + fn pending_arsw(&self, _pool_id: u32, _user: AccountId) -> Result { + Ok(1_000_000_000_000_000_000) + } + + #[ink(message)] + fn deposit( + &mut self, + pool_id: u32, + amount: Balance, + to: AccountId, + ) -> Result<(), FarmingError> { + let (prev_amount, prev_reward_debt) = self + .get_user_info(pool_id, to) + .ok_or(FarmingError::UserNotFound)?; + // TODO: Fix reward_debt + self.data::().user_info.insert( + &(pool_id, to), + &( + prev_amount + .checked_add(amount) + .ok_or(FarmingError::AddOverflow1)?, + prev_reward_debt, + ), + ); + let lp_token = self + .get_lp_token(pool_id) + .ok_or(FarmingError::PoolNotFound2)?; + PSP22Ref::transfer_from( + &lp_token, + Self::env().caller(), + Self::env().account_id(), + amount, + Vec::new(), + )?; + Ok(()) + } + + #[ink(message)] + fn withdraw( + &mut self, + pool_id: u32, + amount: Balance, + to: AccountId, + ) -> Result<(), FarmingError> { + if amount == 0 { + return Err(FarmingError::ZeroWithdrawal) + } + let caller = Self::env().caller(); + let (prev_amount, prev_reward_debt) = self + .get_user_info(pool_id, caller) + .ok_or(FarmingError::UserNotFound)?; + // TODO: Fix reward_debt + self.data::().user_info.insert( + &(pool_id, caller), + &( + prev_amount + .checked_sub(amount) + .ok_or(FarmingError::SubUnderflow2)?, + prev_reward_debt, + ), + ); + let lp_token = self + .get_lp_token(pool_id) + .ok_or(FarmingError::PoolNotFound3)?; + PSP22Ref::transfer(&lp_token, to, amount, Vec::new())?; + Ok(()) + } + + #[ink(message)] + fn harvest(&mut self, _pool_id: u32, _to: AccountId) -> Result<(), FarmingError> { Ok(()) } @@ -58,7 +138,7 @@ pub trait Farming: Storage + Storage + FarmingGetters { fn _update_pool(&mut self, pool_id: u32) -> Result<(), FarmingError> { let pool = self .get_pool_infos(pool_id) - .ok_or(FarmingError::PoolNotFound)?; + .ok_or(FarmingError::PoolNotFound1)?; let current_block = Self::env().block_number(); if current_block > pool.last_reward_block { let lp_token = self @@ -104,12 +184,19 @@ pub trait Farming: Storage + Storage + FarmingGetters { #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] pub enum FarmingError { OwnableError(OwnableError), + PSP22Error(PSP22Error), DuplicateLPToken, - PoolNotFound, + PoolNotFound1, + PoolNotFound2, + PoolNotFound3, + UserNotFound, + ZeroWithdrawal, LpTokenNotFound, LpSupplyIsZero, BlockNumberLowerThanOriginBlock, SubUnderflow1, + SubUnderflow2, + AddOverflow1, } impl From for FarmingError { @@ -117,3 +204,9 @@ impl From for FarmingError { FarmingError::OwnableError(error) } } + +impl From for FarmingError { + fn from(error: PSP22Error) -> Self { + FarmingError::PSP22Error(error) + } +} diff --git a/farming/logics/traits/getters.rs b/farming/logics/traits/getters.rs index 0615b83..b8394ac 100644 --- a/farming/logics/traits/getters.rs +++ b/farming/logics/traits/getters.rs @@ -17,6 +17,11 @@ pub trait FarmingGetters: Storage { self.data::().pool_info.get(&pool_id) } + #[ink(message)] + fn get_user_info(&self, pool_id: u32, user: AccountId) -> Option<(u128, i128)> { + self.data::().user_info.get(&(pool_id, user)) + } + #[ink(message)] fn get_lp_token(&self, pool_id: u32) -> Option { self.data::().lp_tokens.get(pool_id as usize).copied() From 0c0d7a0a598d091d842103c069545ab138c2c6fe Mon Sep 17 00:00:00 2001 From: Hyunggyu Jang Date: Tue, 18 Oct 2022 18:17:45 +0900 Subject: [PATCH 07/36] Implement add correctly --- farming/logics/traits/data.rs | 4 ++-- farming/logics/traits/events.rs | 4 ++-- farming/logics/traits/farming.rs | 30 ++++++++++++++++++++++++++---- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/farming/logics/traits/data.rs b/farming/logics/traits/data.rs index d9212d0..3dc01f3 100644 --- a/farming/logics/traits/data.rs +++ b/farming/logics/traits/data.rs @@ -19,7 +19,7 @@ pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data); pub struct Pool { pub acc_arsw_per_share: u128, pub last_reward_block: u32, - pub alloc_point: u64, + pub alloc_point: u32, } #[derive(Default, Debug)] @@ -47,7 +47,7 @@ pub struct Data { pub lp_tokens: Vec, /// Address of each `rewarder` contract in MasterChef. - pub rewarders: Vec, + pub rewarders: Vec>, /// Total allocation points. Must be the sum of all allocation points in all pools. pub total_alloc_point: u32, diff --git a/farming/logics/traits/events.rs b/farming/logics/traits/events.rs index 91864f4..b199a24 100644 --- a/farming/logics/traits/events.rs +++ b/farming/logics/traits/events.rs @@ -44,9 +44,9 @@ pub trait FarmingEvents { fn _emit_log_pool_addition_event( &self, _pool_id: u32, - _alloc_point: u128, + _alloc_point: u32, _lp_token: AccountId, - _rewarder: AccountId, + _rewarder: Option, ) { } diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index e32e9fa..105883f 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -3,6 +3,7 @@ pub use crate::traits::{ Data, Pool, }, + events::FarmingEvents, getters::FarmingGetters, }; use ink_prelude::vec::Vec; @@ -29,19 +30,38 @@ pub const MAX_PERIOD: u8 = 23u8; pub const FIRST_PERIOD_REWERD_SUPPLY: Balance = 151629858171523000000u128; #[openbrush::trait_definition] -pub trait Farming: Storage + Storage + FarmingGetters { +pub trait Farming: Storage + Storage + FarmingGetters + FarmingEvents { #[ink(message)] #[modifiers(only_owner)] fn add( &mut self, - alloc_point: u128, + alloc_point: u32, lp_token: AccountId, - rewarder: AccountId, + rewarder: Option, ) -> Result<(), FarmingError> { self._check_pool_duplicate(lp_token)?; self._update_all_pools()?; - self.data::().pool_info_length += 1; + self.data::().total_alloc_point = self + .data::() + .total_alloc_point + .checked_add(alloc_point) + .ok_or(FarmingError::AddOverflow2)?; self.data::().lp_tokens.push(lp_token); + self.data::().rewarders.push(rewarder); + let pool_length = self.pool_length(); + + self.data::().pool_info.insert( + &pool_length, + &Pool { + acc_arsw_per_share: 0, + last_reward_block: Self::env().block_number(), + alloc_point, + }, + ); + self.data::().pool_info_length = pool_length + .checked_add(1) + .ok_or(FarmingError::AddOverflow2)?; + self._emit_log_pool_addition_event(pool_length, alloc_point, lp_token, rewarder); Ok(()) } @@ -197,6 +217,8 @@ pub enum FarmingError { SubUnderflow1, SubUnderflow2, AddOverflow1, + AddOverflow2, + AddOverflow3, } impl From for FarmingError { From bcc61926113d3f587340fc321c8b5a67fc2fb9d9 Mon Sep 17 00:00:00 2001 From: Hyunggyu Jang Date: Tue, 18 Oct 2022 18:33:36 +0900 Subject: [PATCH 08/36] Fix deposit (initialization is needed) --- farming/logics/traits/farming.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index 105883f..a5738d7 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -77,9 +77,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far amount: Balance, to: AccountId, ) -> Result<(), FarmingError> { - let (prev_amount, prev_reward_debt) = self - .get_user_info(pool_id, to) - .ok_or(FarmingError::UserNotFound)?; + let (prev_amount, prev_reward_debt) = self.get_user_info(pool_id, to).unwrap_or((0, 0)); // TODO: Fix reward_debt self.data::().user_info.insert( &(pool_id, to), From 8e2dd3a2f5b9eed533084fbdf97a5484cd1b05bd Mon Sep 17 00:00:00 2001 From: Hyunggyu Jang Date: Tue, 18 Oct 2022 20:28:58 +0900 Subject: [PATCH 09/36] Refactor rewarders structure --- farming/logics/traits/data.rs | 2 +- farming/logics/traits/farming.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/farming/logics/traits/data.rs b/farming/logics/traits/data.rs index 3dc01f3..22519bc 100644 --- a/farming/logics/traits/data.rs +++ b/farming/logics/traits/data.rs @@ -47,7 +47,7 @@ pub struct Data { pub lp_tokens: Vec, /// Address of each `rewarder` contract in MasterChef. - pub rewarders: Vec>, + pub rewarders: Mapping, /// Total allocation points. Must be the sum of all allocation points in all pools. pub total_alloc_point: u32, diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index a5738d7..2384cb3 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -47,9 +47,12 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .checked_add(alloc_point) .ok_or(FarmingError::AddOverflow2)?; self.data::().lp_tokens.push(lp_token); - self.data::().rewarders.push(rewarder); let pool_length = self.pool_length(); - + if let Some(rewarder_address) = rewarder { + self.data::() + .rewarders + .insert(&pool_length, &rewarder_address); + } self.data::().pool_info.insert( &pool_length, &Pool { From 031b7fb2c4c594c308cc7282f5c7f9dabf0ed764 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Wed, 19 Oct 2022 13:48:20 +0200 Subject: [PATCH 10/36] updated toolchain --- farming/logics/traits/data.rs | 5 +---- rust-toolchain.toml | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/farming/logics/traits/data.rs b/farming/logics/traits/data.rs index 22519bc..3dc1aa9 100644 --- a/farming/logics/traits/data.rs +++ b/farming/logics/traits/data.rs @@ -12,10 +12,7 @@ use scale::{ pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data); #[derive(Encode, Decode, SpreadLayout, PackedLayout, SpreadAllocate, Default)] -#[cfg_attr( - feature = "std", - derive(Debug, PartialEq, Eq, scale_info::TypeInfo, StorageLayout) -)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo, StorageLayout))] pub struct Pool { pub acc_arsw_per_share: u128, pub last_reward_block: u32, diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 9dd0475..5cfb4e3 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2022-07-24" +channel = "nightly-2022-08-15" components = [ "rustfmt", "clippy" ] targets = [ "wasm32-unknown-unknown"] profile = "minimal" From 0bc28c9335916003f8f47771197a30d4abc33908 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Wed, 19 Oct 2022 16:14:31 +0200 Subject: [PATCH 11/36] Finished update all pools --- farming/contracts/farming/Cargo.toml | 7 +- farming/logics/traits/farming.rs | 133 +++++++++++++++++++++++++-- 2 files changed, 133 insertions(+), 7 deletions(-) diff --git a/farming/contracts/farming/Cargo.toml b/farming/contracts/farming/Cargo.toml index 2f3d162..4473e5e 100644 --- a/farming/contracts/farming/Cargo.toml +++ b/farming/contracts/farming/Cargo.toml @@ -38,4 +38,9 @@ std = [ "openbrush/std", "farming/std" ] -ink-as-dependency = [] + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index 2384cb3..70406be 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -26,7 +26,7 @@ use openbrush::{ pub const ACC_ARSW_PRECISION: u8 = 12; pub const ARTHSWAP_ORIGIN_BLOCK: u32 = 1u32; pub const BLOCK_PER_PERIOD: u32 = 215000u32; -pub const MAX_PERIOD: u8 = 23u8; +pub const MAX_PERIOD: u32 = 23u32; pub const FIRST_PERIOD_REWERD_SUPPLY: Balance = 151629858171523000000u128; #[openbrush::trait_definition] @@ -69,7 +69,12 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } #[ink(message)] - fn pending_arsw(&self, _pool_id: u32, _user: AccountId) -> Result { + fn pending_arsw(&mut self, pool_id: u32, user: AccountId) -> Result { + let mut pool = self + .get_pool_infos(pool_id) + .ok_or(FarmingError::PoolNotFound4)?; + let mut user = self.data::().user_info.get(&(pool_id, user)); + Ok(1_000_000_000_000_000_000) } @@ -157,7 +162,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } fn _update_pool(&mut self, pool_id: u32) -> Result<(), FarmingError> { - let pool = self + let mut pool = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound1)?; let current_block = Self::env().block_number(); @@ -168,15 +173,28 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let lp_supply = PSP22Ref::balance_of(&lp_token, Self::env().account_id()); if lp_supply > 0 { let additional_acc_arsw_per_share = - self._calculate_additional_acc_arsw_per_share(pool, current_block, lp_supply)?; + self._calculate_additional_acc_arsw_per_share(&pool, current_block, lp_supply)?; + pool.acc_arsw_per_share = pool + .acc_arsw_per_share + .checked_add(additional_acc_arsw_per_share) + .ok_or(FarmingError::AddOverflow8)?; } + pool.last_reward_block = current_block; + self.data::().pool_info.insert(pool_id, &pool); + + self._emit_log_update_pool_event( + pool_id, + pool.last_reward_block, + lp_supply, + pool.acc_arsw_per_share, + ); } Ok(()) } fn _calculate_additional_acc_arsw_per_share( &mut self, - pool_info: Pool, + pool_info: &Pool, current_block: u32, lp_supply: Balance, ) -> Result { @@ -185,7 +203,60 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } let last_reward_block_period = self._get_period(pool_info.last_reward_block)?; let current_period = self._get_period(Self::env().block_number())?; - Ok(10u128) + + let mut arsw_reward: Balance = 0; + let mut last_block = pool_info.last_reward_block; + let mut period = last_reward_block_period; + while period <= current_period { + if period > MAX_PERIOD { + break + } + let total_alloc_point: u32 = self.data::().total_alloc_point; + if current_block <= self._period_max(period)? { + arsw_reward = arsw_reward + .checked_add( + (current_block as u128) + .checked_sub(last_block as u128) + .ok_or(FarmingError::SubUnderflow4)? + .checked_mul(self._arsw_per_block(period)?) + .ok_or(FarmingError::MulOverflow3)? + .checked_mul(pool_info.alloc_point as u128) + .ok_or(FarmingError::MulOverflow4)? + .into(), + ) + .ok_or(FarmingError::AddOverflow6)? + .checked_div(total_alloc_point.into()) + .ok_or(FarmingError::DivByZero1)? + } else { + arsw_reward = arsw_reward + .checked_add( + (self._period_max(period)? as u128) + .checked_sub(last_block.into()) + .ok_or(FarmingError::SubUnderflow5)? + .checked_mul(self._arsw_per_block(period)? as u128) + .ok_or(FarmingError::MulOverflow5)? + .checked_mul( + pool_info + .alloc_point + .checked_div(total_alloc_point) + .ok_or(FarmingError::DivByZero2)? + .into(), + ) + .ok_or(FarmingError::MulOverflow6)? + .into(), + ) + .ok_or(FarmingError::AddOverflow7)?; + last_block = self._period_max(period)?; + } + + period += 1; + } + + Ok(arsw_reward + .checked_mul(ACC_ARSW_PRECISION.into()) + .ok_or(FarmingError::MulOverflow8)? + .checked_div(lp_supply) + .ok_or(FarmingError::DivByZero3)?) } fn _get_period(&self, block_number: u32) -> Result { @@ -199,6 +270,34 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::SubUnderflow1)? / BLOCK_PER_PERIOD) } + + fn _period_max(&self, period: u32) -> Result { + Ok(ARTHSWAP_ORIGIN_BLOCK + .checked_add( + BLOCK_PER_PERIOD + .checked_mul(period.checked_add(1).ok_or(FarmingError::AddOverflow4)?) + .ok_or(FarmingError::MulOverflow1)?, + ) + .ok_or(FarmingError::AddOverflow5)? + .checked_sub(1) + .ok_or(FarmingError::SubUnderflow3)?) + } + + fn _arsw_per_block(&self, period: u32) -> Result { + if period > MAX_PERIOD { + return Ok(0) + } + Ok(FIRST_PERIOD_REWERD_SUPPLY + .checked_mul( + 9u128 + .checked_pow(period) + .ok_or(FarmingError::PowOverflow1)? + / 10u128 + .checked_pow(period) + .ok_or(FarmingError::PowOverflow2)?, + ) + .ok_or(FarmingError::MulOverflow2)?) + } } #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] @@ -210,6 +309,7 @@ pub enum FarmingError { PoolNotFound1, PoolNotFound2, PoolNotFound3, + PoolNotFound4, UserNotFound, ZeroWithdrawal, LpTokenNotFound, @@ -217,9 +317,30 @@ pub enum FarmingError { BlockNumberLowerThanOriginBlock, SubUnderflow1, SubUnderflow2, + SubUnderflow3, + SubUnderflow4, + SubUnderflow5, AddOverflow1, AddOverflow2, AddOverflow3, + AddOverflow4, + AddOverflow5, + AddOverflow6, + AddOverflow7, + AddOverflow8, + MulOverflow1, + MulOverflow2, + MulOverflow3, + MulOverflow4, + MulOverflow5, + MulOverflow6, + MulOverflow7, + MulOverflow8, + PowOverflow1, + PowOverflow2, + DivByZero1, + DivByZero2, + DivByZero3, } impl From for FarmingError { From 9818239361d5654384b9fdb38635af30e5142f59 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Wed, 19 Oct 2022 16:49:11 +0200 Subject: [PATCH 12/36] pending arsw --- farming/logics/traits/data.rs | 14 ++++++- farming/logics/traits/farming.rs | 67 ++++++++++++++++++++++++-------- farming/logics/traits/getters.rs | 7 +++- 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/farming/logics/traits/data.rs b/farming/logics/traits/data.rs index 3dc1aa9..8ca6f19 100644 --- a/farming/logics/traits/data.rs +++ b/farming/logics/traits/data.rs @@ -3,7 +3,10 @@ use ink_storage::{ traits::*, Mapping, }; -use openbrush::traits::AccountId; +use openbrush::traits::{ + AccountId, + Balance, +}; use scale::{ Decode, Encode, @@ -19,6 +22,13 @@ pub struct Pool { pub alloc_point: u32, } +#[derive(Encode, Decode, SpreadLayout, PackedLayout, SpreadAllocate, Default)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo, StorageLayout))] +pub struct UserInfo { + pub amount: Balance, + pub reward_debt: i128, +} + #[derive(Default, Debug)] #[openbrush::upgradeable_storage(STORAGE_KEY)] pub struct Data { @@ -30,7 +40,7 @@ pub struct Data { /// Value (`amount`: u128, `reward_debt`: u128) /// `amount` LP token amount the user has provided. /// `reward_debt` The amount of ARSW entitled to the user. - pub user_info: Mapping<(u32, AccountId), (u128, i128)>, + pub user_info: Mapping<(u32, AccountId), UserInfo>, /// Info of each MasterChef pool. /// Key `pool_id`: u32 diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index 70406be..c6c27c6 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -1,3 +1,4 @@ +use crate::traits::data::UserInfo; pub use crate::traits::{ data::{ Data, @@ -41,6 +42,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far ) -> Result<(), FarmingError> { self._check_pool_duplicate(lp_token)?; self._update_all_pools()?; + self.data::().total_alloc_point = self .data::() .total_alloc_point @@ -48,6 +50,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::AddOverflow2)?; self.data::().lp_tokens.push(lp_token); let pool_length = self.pool_length(); + if let Some(rewarder_address) = rewarder { self.data::() .rewarders @@ -64,6 +67,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far self.data::().pool_info_length = pool_length .checked_add(1) .ok_or(FarmingError::AddOverflow2)?; + self._emit_log_pool_addition_event(pool_length, alloc_point, lp_token, rewarder); Ok(()) } @@ -73,9 +77,30 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let mut pool = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound4)?; - let mut user = self.data::().user_info.get(&(pool_id, user)); + let mut user_info = self + .get_user_info(pool_id, user) + .ok_or(FarmingError::UserNotFound)?; + let mut acc_arsw_per_share = pool.acc_arsw_per_share; + + let lp_supply = self._get_lp_supply(pool_id)?; + let current_block = Self::env().block_number(); + + if current_block > pool.last_reward_block && lp_supply != 0 { + let additional_acc_arsw_per_share = + self._calculate_additional_acc_arsw_per_share(&pool, current_block, lp_supply)?; + acc_arsw_per_share = acc_arsw_per_share + .checked_add(additional_acc_arsw_per_share) + .ok_or(FarmingError::AddOverflow8)?; + } - Ok(1_000_000_000_000_000_000) + let pending = (user_info + .amount + .checked_mul(acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow9)? + / ACC_ARSW_PRECISION) + .checked_sub(user_info.reward_debt) + .ok_or(FarmingError::SubUnderflow6)?; + Ok(pending) } #[ink(message)] @@ -85,16 +110,17 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far amount: Balance, to: AccountId, ) -> Result<(), FarmingError> { - let (prev_amount, prev_reward_debt) = self.get_user_info(pool_id, to).unwrap_or((0, 0)); + let user_info = self.get_user_info(pool_id, to).unwrap_or_default(); // TODO: Fix reward_debt self.data::().user_info.insert( &(pool_id, to), - &( - prev_amount + &UserInfo { + amount: user_info + .amount .checked_add(amount) .ok_or(FarmingError::AddOverflow1)?, - prev_reward_debt, - ), + reward_debt: user_info.reward_debt, + }, ); let lp_token = self .get_lp_token(pool_id) @@ -120,18 +146,19 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far return Err(FarmingError::ZeroWithdrawal) } let caller = Self::env().caller(); - let (prev_amount, prev_reward_debt) = self + let user_info = self .get_user_info(pool_id, caller) .ok_or(FarmingError::UserNotFound)?; // TODO: Fix reward_debt self.data::().user_info.insert( - &(pool_id, caller), - &( - prev_amount + &(pool_id, to), + &UserInfo { + amount: user_info + .amount .checked_sub(amount) .ok_or(FarmingError::SubUnderflow2)?, - prev_reward_debt, - ), + reward_debt: user_info.reward_debt, + }, ); let lp_token = self .get_lp_token(pool_id) @@ -167,10 +194,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::PoolNotFound1)?; let current_block = Self::env().block_number(); if current_block > pool.last_reward_block { - let lp_token = self - .get_lp_token(pool_id) - .ok_or(FarmingError::LpTokenNotFound)?; - let lp_supply = PSP22Ref::balance_of(&lp_token, Self::env().account_id()); + let lp_supply = self._get_lp_supply(pool_id)?; if lp_supply > 0 { let additional_acc_arsw_per_share = self._calculate_additional_acc_arsw_per_share(&pool, current_block, lp_supply)?; @@ -298,6 +322,13 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far ) .ok_or(FarmingError::MulOverflow2)?) } + + fn _get_lp_supply(&self, pool_id: u32) -> Result { + let lp_token = self + .get_lp_token(pool_id) + .ok_or(FarmingError::LpTokenNotFound)?; + Ok(PSP22Ref::balance_of(&lp_token, Self::env().account_id())) + } } #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] @@ -320,6 +351,7 @@ pub enum FarmingError { SubUnderflow3, SubUnderflow4, SubUnderflow5, + SubUnderflow6, AddOverflow1, AddOverflow2, AddOverflow3, @@ -336,6 +368,7 @@ pub enum FarmingError { MulOverflow6, MulOverflow7, MulOverflow8, + MulOverflow9, PowOverflow1, PowOverflow2, DivByZero1, diff --git a/farming/logics/traits/getters.rs b/farming/logics/traits/getters.rs index b8394ac..80af784 100644 --- a/farming/logics/traits/getters.rs +++ b/farming/logics/traits/getters.rs @@ -1,5 +1,8 @@ use crate::traits::{ - data::Pool, + data::{ + Pool, + UserInfo, + }, farming::Data, }; use ink_env::AccountId; @@ -18,7 +21,7 @@ pub trait FarmingGetters: Storage { } #[ink(message)] - fn get_user_info(&self, pool_id: u32, user: AccountId) -> Option<(u128, i128)> { + fn get_user_info(&self, pool_id: u32, user: AccountId) -> Option { self.data::().user_info.get(&(pool_id, user)) } From d775935d49706f4d4afab08fcb7c8160a0523ba7 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Wed, 19 Oct 2022 17:19:05 +0200 Subject: [PATCH 13/36] set function --- farming/logics/traits/events.rs | 4 +- farming/logics/traits/farming.rs | 71 +++++++++++++++++++++++++++----- farming/logics/traits/getters.rs | 5 +++ 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/farming/logics/traits/events.rs b/farming/logics/traits/events.rs index b199a24..48d50a1 100644 --- a/farming/logics/traits/events.rs +++ b/farming/logics/traits/events.rs @@ -53,8 +53,8 @@ pub trait FarmingEvents { fn _emit_log_set_pool_event( &self, _pool_id: u32, - _alloc_point: u128, - _rewardes: AccountId, + _alloc_point: u32, + _rewarder: AccountId, _overwrite: bool, ) { } diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index c6c27c6..fef9892 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -72,12 +72,51 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far Ok(()) } + #[ink(message)] + #[modifiers(only_owner)] + fn set( + &mut self, + pool_id: u32, + alloc_point: u32, + rewarder: AccountId, + overwrite: bool, + ) -> Result<(), FarmingError> { + self._update_all_pools()?; + let pool_info = self + .get_pool_infos(pool_id) + .ok_or(FarmingError::PoolNotFound5)?; + self.data::().total_alloc_point = self + .data::() + .total_alloc_point + .checked_sub(pool_info.alloc_point) + .ok_or(FarmingError::SubUnderflow7)? + .checked_add(alloc_point) + .ok_or(FarmingError::AddOverflow9)?; + + self.data::().pool_info.insert( + &pool_id, + &Pool { + alloc_point, + ..pool_info + }, + ); + let mut rewarder = rewarder; + if overwrite { + self.data::().rewarders.insert(&pool_id, &rewarder); + rewarder = self + .get_rewarder(pool_id) + .ok_or(FarmingError::RewarderNotFound)?; + } + self._emit_log_set_pool_event(pool_id, alloc_point, rewarder, overwrite); + Ok(()) + } + #[ink(message)] fn pending_arsw(&mut self, pool_id: u32, user: AccountId) -> Result { - let mut pool = self + let pool = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound4)?; - let mut user_info = self + let user_info = self .get_user_info(pool_id, user) .ok_or(FarmingError::UserNotFound)?; let mut acc_arsw_per_share = pool.acc_arsw_per_share; @@ -93,14 +132,20 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::AddOverflow8)?; } - let pending = (user_info - .amount - .checked_mul(acc_arsw_per_share) - .ok_or(FarmingError::MulOverflow9)? - / ACC_ARSW_PRECISION) - .checked_sub(user_info.reward_debt) - .ok_or(FarmingError::SubUnderflow6)?; - Ok(pending) + let pending = >::try_into( + user_info + .amount + .checked_mul(acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow9)? + / ACC_ARSW_PRECISION as u128, + ) + .map_err(|_| FarmingError::CastToi128Error)? + .checked_sub(user_info.reward_debt) + .ok_or(FarmingError::SubUnderflow6)?; + Ok( + >::try_into(pending) + .map_err(|_| FarmingError::CastTou128Error)?, + ) } #[ink(message)] @@ -341,17 +386,22 @@ pub enum FarmingError { PoolNotFound2, PoolNotFound3, PoolNotFound4, + PoolNotFound5, UserNotFound, ZeroWithdrawal, LpTokenNotFound, LpSupplyIsZero, BlockNumberLowerThanOriginBlock, + CastToi128Error, + CastTou128Error, + RewarderNotFound, SubUnderflow1, SubUnderflow2, SubUnderflow3, SubUnderflow4, SubUnderflow5, SubUnderflow6, + SubUnderflow7, AddOverflow1, AddOverflow2, AddOverflow3, @@ -360,6 +410,7 @@ pub enum FarmingError { AddOverflow6, AddOverflow7, AddOverflow8, + AddOverflow9, MulOverflow1, MulOverflow2, MulOverflow3, diff --git a/farming/logics/traits/getters.rs b/farming/logics/traits/getters.rs index 80af784..6ad2e10 100644 --- a/farming/logics/traits/getters.rs +++ b/farming/logics/traits/getters.rs @@ -29,4 +29,9 @@ pub trait FarmingGetters: Storage { fn get_lp_token(&self, pool_id: u32) -> Option { self.data::().lp_tokens.get(pool_id as usize).copied() } + + #[ink(message)] + fn get_rewarder(&self, pool_id: u32) -> Option { + self.data::().rewarders.get(pool_id) + } } From 164f293a6c440f9a3f37f52c3c9cd9aa4a97d0ab Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Wed, 19 Oct 2022 17:32:31 +0200 Subject: [PATCH 14/36] fix mut of var --- farming/logics/traits/farming.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index 947b049..ef9da18 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -234,7 +234,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } fn _update_pool(&mut self, pool_id: u32) -> Result<(), FarmingError> { - let pool = self + let mut pool = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound1)?; let current_block = Self::env().block_number(); From b5d89eab61c7eb6385f4587fc728522480457c6a Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Wed, 19 Oct 2022 17:35:39 +0200 Subject: [PATCH 15/36] fmt --- farming/logics/traits/data.rs | 2 -- farming/logics/traits/getters.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/farming/logics/traits/data.rs b/farming/logics/traits/data.rs index 22518fd..8ca6f19 100644 --- a/farming/logics/traits/data.rs +++ b/farming/logics/traits/data.rs @@ -40,10 +40,8 @@ pub struct Data { /// Value (`amount`: u128, `reward_debt`: u128) /// `amount` LP token amount the user has provided. /// `reward_debt` The amount of ARSW entitled to the user. - pub user_info: Mapping<(u32, AccountId), UserInfo>, - /// Info of each MasterChef pool. /// Key `pool_id`: u32 /// Value Pool (`acc_arsw_per_share`: u128, `last_reward_block`: u32, `alloc_point`: u64 ) diff --git a/farming/logics/traits/getters.rs b/farming/logics/traits/getters.rs index eeb9a65..6ad2e10 100644 --- a/farming/logics/traits/getters.rs +++ b/farming/logics/traits/getters.rs @@ -3,7 +3,6 @@ use crate::traits::{ Pool, UserInfo, }, - farming::Data, }; use ink_env::AccountId; @@ -23,7 +22,6 @@ pub trait FarmingGetters: Storage { #[ink(message)] fn get_user_info(&self, pool_id: u32, user: AccountId) -> Option { - self.data::().user_info.get(&(pool_id, user)) } @@ -36,5 +34,4 @@ pub trait FarmingGetters: Storage { fn get_rewarder(&self, pool_id: u32) -> Option { self.data::().rewarders.get(pool_id) } - } From c9d46ec0a2fb79b4acf526abe356373096d247e1 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Thu, 20 Oct 2022 10:43:07 +0200 Subject: [PATCH 16/36] clean code - pr comments --- farming/logics/traits/events.rs | 2 +- farming/logics/traits/farming.rs | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/farming/logics/traits/events.rs b/farming/logics/traits/events.rs index 48d50a1..939b8fd 100644 --- a/farming/logics/traits/events.rs +++ b/farming/logics/traits/events.rs @@ -54,7 +54,7 @@ pub trait FarmingEvents { &self, _pool_id: u32, _alloc_point: u32, - _rewarder: AccountId, + _rewarder: Option, _overwrite: bool, ) { } diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index ef9da18..e3340d1 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -24,7 +24,7 @@ use openbrush::{ }, }; -pub const ACC_ARSW_PRECISION: u8 = 12; +pub const ACC_ARSW_PRECISION: u128 = 1_000_000_000_000; pub const ARTHSWAP_ORIGIN_BLOCK: u32 = 1u32; pub const BLOCK_PER_PERIOD: u32 = 215000u32; pub const MAX_PERIOD: u32 = 23u32; @@ -78,13 +78,13 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far &mut self, pool_id: u32, alloc_point: u32, - rewarder: AccountId, + rewarder: Option, overwrite: bool, ) -> Result<(), FarmingError> { - self._update_all_pools()?; let pool_info = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound5)?; + self._update_all_pools()?; self.data::().total_alloc_point = self .data::() .total_alloc_point @@ -102,10 +102,16 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far ); let mut rewarder = rewarder; if overwrite { - self.data::().rewarders.insert(&pool_id, &rewarder); - rewarder = self - .get_rewarder(pool_id) - .ok_or(FarmingError::RewarderNotFound)?; + match rewarder { + Some(rewarder_address) => { + self.data::() + .rewarders + .insert(&pool_id, &rewarder_address) + } + None => self.data::().rewarders.remove(&pool_id), + } + } else { + rewarder = self.get_rewarder(pool_id); } self._emit_log_set_pool_event(pool_id, alloc_point, rewarder, overwrite); Ok(()) @@ -137,7 +143,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .amount .checked_mul(acc_arsw_per_share) .ok_or(FarmingError::MulOverflow9)? - / ACC_ARSW_PRECISION as u128, + / ACC_ARSW_PRECISION, ) .map_err(|_| FarmingError::CastToi128Error)? .checked_sub(user_info.reward_debt) @@ -322,7 +328,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } Ok(arsw_reward - .checked_mul(ACC_ARSW_PRECISION.into()) + .checked_mul(ACC_ARSW_PRECISION) .ok_or(FarmingError::MulOverflow8)? .checked_div(lp_supply) .ok_or(FarmingError::DivByZero3)?) From d71ec073d1886ca5ea98a41f40afb4c2631700ba Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Thu, 20 Oct 2022 14:51:37 +0200 Subject: [PATCH 17/36] refactor file structure --- farming/contracts/farming/lib.rs | 2 +- .../logics/traits/{ => master_chef}/data.rs | 0 farming/logics/traits/master_chef/errors.rs | 71 +++++++++++ .../logics/traits/{ => master_chef}/events.rs | 0 .../traits/{ => master_chef}/farming.rs | 120 ++++++------------ .../traits/{ => master_chef}/getters.rs | 2 +- farming/logics/traits/master_chef/mod.rs | 5 + farming/logics/traits/mod.rs | 6 +- farming/logics/traits/rewarder/mod.rs | 1 + farming/logics/traits/rewarder/rewarder.rs | 0 10 files changed, 121 insertions(+), 86 deletions(-) rename farming/logics/traits/{ => master_chef}/data.rs (100%) create mode 100644 farming/logics/traits/master_chef/errors.rs rename farming/logics/traits/{ => master_chef}/events.rs (100%) rename farming/logics/traits/{ => master_chef}/farming.rs (86%) rename farming/logics/traits/{ => master_chef}/getters.rs (96%) create mode 100644 farming/logics/traits/master_chef/mod.rs create mode 100644 farming/logics/traits/rewarder/mod.rs create mode 100644 farming/logics/traits/rewarder/rewarder.rs diff --git a/farming/contracts/farming/lib.rs b/farming/contracts/farming/lib.rs index 0436cf7..6d17803 100644 --- a/farming/contracts/farming/lib.rs +++ b/farming/contracts/farming/lib.rs @@ -3,7 +3,7 @@ #[openbrush::contract] pub mod farming { - use farming::traits::{ + use farming::traits::master_chef::{ events::*, farming::*, getters::*, diff --git a/farming/logics/traits/data.rs b/farming/logics/traits/master_chef/data.rs similarity index 100% rename from farming/logics/traits/data.rs rename to farming/logics/traits/master_chef/data.rs diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs new file mode 100644 index 0000000..aa3b002 --- /dev/null +++ b/farming/logics/traits/master_chef/errors.rs @@ -0,0 +1,71 @@ +use openbrush::contracts::{ + ownable::*, + traits::psp22::PSP22Error, +}; + +#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] +pub enum FarmingError { + OwnableError(OwnableError), + PSP22Error(PSP22Error), + DuplicateLPToken, + PoolNotFound1, + PoolNotFound2, + PoolNotFound3, + PoolNotFound4, + PoolNotFound5, + UserNotFound, + ZeroWithdrawal, + LpTokenNotFound, + LpSupplyIsZero, + BlockNumberLowerThanOriginBlock, + CastToi128Error, + CastTou128Error1, + CastToi128Error2, + RewarderNotFound, + SubUnderflow1, + SubUnderflow2, + SubUnderflow3, + SubUnderflow4, + SubUnderflow5, + SubUnderflow6, + SubUnderflow7, + AddOverflow1, + AddOverflow2, + AddOverflow3, + AddOverflow4, + AddOverflow5, + AddOverflow6, + AddOverflow7, + AddOverflow8, + AddOverflow9, + AddOverflow10, + AddOverflow11, + MulOverflow1, + MulOverflow2, + MulOverflow3, + MulOverflow4, + MulOverflow5, + MulOverflow6, + MulOverflow7, + MulOverflow8, + MulOverflow9, + MulOverflow10, + PowOverflow1, + PowOverflow2, + DivByZero1, + DivByZero2, + DivByZero3, +} + +impl From for FarmingError { + fn from(error: OwnableError) -> Self { + FarmingError::OwnableError(error) + } +} + +impl From for FarmingError { + fn from(error: PSP22Error) -> Self { + FarmingError::PSP22Error(error) + } +} diff --git a/farming/logics/traits/events.rs b/farming/logics/traits/master_chef/events.rs similarity index 100% rename from farming/logics/traits/events.rs rename to farming/logics/traits/master_chef/events.rs diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/master_chef/farming.rs similarity index 86% rename from farming/logics/traits/farming.rs rename to farming/logics/traits/master_chef/farming.rs index e3340d1..e301abd 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -1,5 +1,8 @@ -use crate::traits::data::UserInfo; -pub use crate::traits::{ +use crate::traits::master_chef::{ + data::UserInfo, + errors::FarmingError, +}; +pub use crate::traits::master_chef::{ data::{ Data, Pool, @@ -11,19 +14,18 @@ use ink_prelude::vec::Vec; use openbrush::{ contracts::{ ownable::*, - traits::psp22::{ - PSP22Error, - PSP22Ref, - }, + traits::psp22::PSP22Ref, }, modifiers, traits::{ AccountId, Balance, Storage, + ZERO_ADDRESS, }, }; +// Cannot be 0 or it will panic! pub const ACC_ARSW_PRECISION: u128 = 1_000_000_000_000; pub const ARTHSWAP_ORIGIN_BLOCK: u32 = 1u32; pub const BLOCK_PER_PERIOD: u32 = 215000u32; @@ -148,10 +150,8 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .map_err(|_| FarmingError::CastToi128Error)? .checked_sub(user_info.reward_debt) .ok_or(FarmingError::SubUnderflow6)?; - Ok( - >::try_into(pending) - .map_err(|_| FarmingError::CastTou128Error)?, - ) + Ok(>::try_into(pending) + .map_err(|_| FarmingError::CastTou128Error1)?) } #[ink(message)] @@ -161,18 +161,41 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far amount: Balance, to: AccountId, ) -> Result<(), FarmingError> { - let user_info = self.get_user_info(pool_id, to).unwrap_or_default(); - // TODO: Fix reward_debt + let pool = self + .get_pool_infos(pool_id) + .ok_or(FarmingError::PoolNotFound4)?; + let user = self.get_user_info(pool_id, to).unwrap_or_default(); + let user_amount = user + .amount + .checked_add(amount) + .ok_or(FarmingError::AddOverflow10)?; + let user_reward_debt = user + .reward_debt + .checked_add( + >::try_into( + amount + .checked_mul(pool.acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow10)? + / ACC_ARSW_PRECISION, + ) + .map_err(|_| FarmingError::CastToi128Error2)?, + ) + .ok_or(FarmingError::AddOverflow11)?; + self.data::().user_info.insert( &(pool_id, to), &UserInfo { - amount: user_info - .amount - .checked_add(amount) - .ok_or(FarmingError::AddOverflow1)?, - reward_debt: user_info.reward_debt, + amount: user_amount, + reward_debt: user_reward_debt, }, ); + + if let Some(rewarder_address) = self.get_rewarder(pool_id) { + if rewarder_address != ZERO_ADDRESS.into() { + // rewarder.onARSWReward(pid, to, to, 0, user.amount); + } + } + let lp_token = self .get_lp_token(pool_id) .ok_or(FarmingError::PoolNotFound2)?; @@ -380,66 +403,3 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far Ok(PSP22Ref::balance_of(&lp_token, Self::env().account_id())) } } - -#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] -#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] -pub enum FarmingError { - OwnableError(OwnableError), - PSP22Error(PSP22Error), - DuplicateLPToken, - PoolNotFound1, - PoolNotFound2, - PoolNotFound3, - PoolNotFound4, - PoolNotFound5, - UserNotFound, - ZeroWithdrawal, - LpTokenNotFound, - LpSupplyIsZero, - BlockNumberLowerThanOriginBlock, - CastToi128Error, - CastTou128Error, - RewarderNotFound, - SubUnderflow1, - SubUnderflow2, - SubUnderflow3, - SubUnderflow4, - SubUnderflow5, - SubUnderflow6, - SubUnderflow7, - AddOverflow1, - AddOverflow2, - AddOverflow3, - AddOverflow4, - AddOverflow5, - AddOverflow6, - AddOverflow7, - AddOverflow8, - AddOverflow9, - MulOverflow1, - MulOverflow2, - MulOverflow3, - MulOverflow4, - MulOverflow5, - MulOverflow6, - MulOverflow7, - MulOverflow8, - MulOverflow9, - PowOverflow1, - PowOverflow2, - DivByZero1, - DivByZero2, - DivByZero3, -} - -impl From for FarmingError { - fn from(error: OwnableError) -> Self { - FarmingError::OwnableError(error) - } -} - -impl From for FarmingError { - fn from(error: PSP22Error) -> Self { - FarmingError::PSP22Error(error) - } -} diff --git a/farming/logics/traits/getters.rs b/farming/logics/traits/master_chef/getters.rs similarity index 96% rename from farming/logics/traits/getters.rs rename to farming/logics/traits/master_chef/getters.rs index 6ad2e10..583e3a5 100644 --- a/farming/logics/traits/getters.rs +++ b/farming/logics/traits/master_chef/getters.rs @@ -1,4 +1,4 @@ -use crate::traits::{ +use crate::traits::master_chef::{ data::{ Pool, UserInfo, diff --git a/farming/logics/traits/master_chef/mod.rs b/farming/logics/traits/master_chef/mod.rs new file mode 100644 index 0000000..38029af --- /dev/null +++ b/farming/logics/traits/master_chef/mod.rs @@ -0,0 +1,5 @@ +pub mod data; +pub mod errors; +pub mod events; +pub mod farming; +pub mod getters; diff --git a/farming/logics/traits/mod.rs b/farming/logics/traits/mod.rs index 321934a..207f3e2 100644 --- a/farming/logics/traits/mod.rs +++ b/farming/logics/traits/mod.rs @@ -1,4 +1,2 @@ -pub mod data; -pub mod events; -pub mod farming; -pub mod getters; +pub mod master_chef; +pub mod rewarder; diff --git a/farming/logics/traits/rewarder/mod.rs b/farming/logics/traits/rewarder/mod.rs new file mode 100644 index 0000000..5776dfc --- /dev/null +++ b/farming/logics/traits/rewarder/mod.rs @@ -0,0 +1 @@ +pub mod rewarder; diff --git a/farming/logics/traits/rewarder/rewarder.rs b/farming/logics/traits/rewarder/rewarder.rs new file mode 100644 index 0000000..e69de29 From f1482481afddc75b4b30b62d94a431df5d5e37ea Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 21 Oct 2022 11:24:55 +0200 Subject: [PATCH 18/36] Impl rewarder --- farming/contracts/rewarder/Cargo.toml | 45 ++++++++++++ farming/contracts/rewarder/lib.rs | 42 +++++++++++ farming/logics/traits/master_chef/errors.rs | 8 +++ farming/logics/traits/master_chef/farming.rs | 17 +++-- farming/logics/traits/rewarder/data.rs | 11 +++ farming/logics/traits/rewarder/errors.rs | 16 +++++ farming/logics/traits/rewarder/getters.rs | 21 ++++++ farming/logics/traits/rewarder/mod.rs | 3 + farming/logics/traits/rewarder/rewarder.rs | 74 ++++++++++++++++++++ 9 files changed, 230 insertions(+), 7 deletions(-) create mode 100644 farming/contracts/rewarder/Cargo.toml create mode 100644 farming/contracts/rewarder/lib.rs create mode 100644 farming/logics/traits/rewarder/data.rs create mode 100644 farming/logics/traits/rewarder/errors.rs create mode 100644 farming/logics/traits/rewarder/getters.rs diff --git a/farming/contracts/rewarder/Cargo.toml b/farming/contracts/rewarder/Cargo.toml new file mode 100644 index 0000000..66fea6e --- /dev/null +++ b/farming/contracts/rewarder/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "rewarder_contract" +version = "0.1.0" +authors = ["Stake Technologies "] +edition = "2021" + +[dependencies] +ink_primitives = { version = "~3.3.0", default-features = false } +ink_metadata = { version = "~3.3.0", default-features = false, features = ["derive"], optional = true } +ink_env = { version = "~3.3.0", default-features = false } +ink_storage = { version = "~3.3.0", default-features = false } +ink_lang = { version = "~3.3.0", default-features = false } +ink_prelude = { version = "~3.3.0", default-features = false } + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } + +openbrush = { version = "2.2.0", default-features = false, features = ["psp22"] } +farming = { path = "../../logics", default-features = false } + +[lib] +name = "rewarder_contract" +path = "lib.rs" +crate-type = ["cdylib"] + +[features] +default = ["std"] +std = [ + "ink_primitives/std", + "ink_metadata", + "ink_metadata/std", + "ink_env/std", + "ink_storage/std", + "ink_lang/std", + "scale/std", + "scale-info", + "scale-info/std", + "openbrush/std", + "farming/std" +] +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false diff --git a/farming/contracts/rewarder/lib.rs b/farming/contracts/rewarder/lib.rs new file mode 100644 index 0000000..882db94 --- /dev/null +++ b/farming/contracts/rewarder/lib.rs @@ -0,0 +1,42 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![feature(min_specialization)] + +#[openbrush::contract] +pub mod rewarder { + use farming::traits::rewarder::{ + data::*, + getters::*, + rewarder::*, + }; + use ink_storage::traits::SpreadAllocate; + use openbrush::traits::Storage; + + #[ink(storage)] + #[derive(Default, SpreadAllocate, Storage)] + pub struct Rewarderontract { + #[storage_field] + rewarder: Data, + } + + impl Rewarder for Rewarderontract {} + + impl RewarderGetters for Rewarderontract {} + + impl Rewarderontract { + #[ink(constructor)] + pub fn new( + reward_multiplier: u32, + reward_token: AccountId, + master_chef: AccountId, + ) -> Self { + ink_lang::codegen::initialize_contract(|instance: &mut Self| { + instance.rewarder.reward_multiplier = reward_multiplier; + instance.rewarder.reward_token = reward_token; + instance.rewarder.master_chef = master_chef; + }) + } + + #[ink(message)] + pub fn dummy(&self) {} + } +} diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs index aa3b002..55c3f21 100644 --- a/farming/logics/traits/master_chef/errors.rs +++ b/farming/logics/traits/master_chef/errors.rs @@ -1,3 +1,4 @@ +use crate::traits::rewarder::errors::RewarderError; use openbrush::contracts::{ ownable::*, traits::psp22::PSP22Error, @@ -8,6 +9,7 @@ use openbrush::contracts::{ pub enum FarmingError { OwnableError(OwnableError), PSP22Error(PSP22Error), + RewarderError(RewarderError), DuplicateLPToken, PoolNotFound1, PoolNotFound2, @@ -69,3 +71,9 @@ impl From for FarmingError { FarmingError::PSP22Error(error) } } + +impl From for FarmingError { + fn from(error: RewarderError) -> Self { + FarmingError::RewarderError(error) + } +} diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index e301abd..2dfe568 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -2,13 +2,16 @@ use crate::traits::master_chef::{ data::UserInfo, errors::FarmingError, }; -pub use crate::traits::master_chef::{ - data::{ - Data, - Pool, +pub use crate::traits::{ + master_chef::{ + data::{ + Data, + Pool, + }, + events::FarmingEvents, + getters::FarmingGetters, }, - events::FarmingEvents, - getters::FarmingGetters, + rewarder::rewarder::RewarderRef, }; use ink_prelude::vec::Vec; use openbrush::{ @@ -192,7 +195,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far if let Some(rewarder_address) = self.get_rewarder(pool_id) { if rewarder_address != ZERO_ADDRESS.into() { - // rewarder.onARSWReward(pid, to, to, 0, user.amount); + RewarderRef::on_arsw_reward(&rewarder_address, to, to, user_amount)?; } } diff --git a/farming/logics/traits/rewarder/data.rs b/farming/logics/traits/rewarder/data.rs new file mode 100644 index 0000000..55fcc4a --- /dev/null +++ b/farming/logics/traits/rewarder/data.rs @@ -0,0 +1,11 @@ +use ink_env::AccountId; + +pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data); + +#[derive(Default, Debug)] +#[openbrush::upgradeable_storage(STORAGE_KEY)] +pub struct Data { + pub reward_multiplier: u32, + pub reward_token: AccountId, + pub master_chef: AccountId, +} diff --git a/farming/logics/traits/rewarder/errors.rs b/farming/logics/traits/rewarder/errors.rs new file mode 100644 index 0000000..8942614 --- /dev/null +++ b/farming/logics/traits/rewarder/errors.rs @@ -0,0 +1,16 @@ +use openbrush::contracts::traits::psp22::PSP22Error; + +#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] +pub enum RewarderError { + PSP22Error(PSP22Error), + CallerIsNotMasterChef, + MulOverflow1, + MulOverflow2, +} + +impl From for RewarderError { + fn from(error: PSP22Error) -> Self { + RewarderError::PSP22Error(error) + } +} diff --git a/farming/logics/traits/rewarder/getters.rs b/farming/logics/traits/rewarder/getters.rs new file mode 100644 index 0000000..c358ed5 --- /dev/null +++ b/farming/logics/traits/rewarder/getters.rs @@ -0,0 +1,21 @@ +use crate::traits::rewarder::rewarder::Data; +use ink_env::AccountId; +use openbrush::traits::Storage; + +#[openbrush::trait_definition] +pub trait RewarderGetters: Storage { + #[ink(message)] + fn reward_multiplier(&self) -> u32 { + self.data::().reward_multiplier + } + + #[ink(message)] + fn reward_token(&self) -> AccountId { + self.data::().reward_token + } + + #[ink(message)] + fn master_chef(&self) -> AccountId { + self.data::().master_chef + } +} diff --git a/farming/logics/traits/rewarder/mod.rs b/farming/logics/traits/rewarder/mod.rs index 5776dfc..38b2235 100644 --- a/farming/logics/traits/rewarder/mod.rs +++ b/farming/logics/traits/rewarder/mod.rs @@ -1 +1,4 @@ +pub mod data; +pub mod errors; +pub mod getters; pub mod rewarder; diff --git a/farming/logics/traits/rewarder/rewarder.rs b/farming/logics/traits/rewarder/rewarder.rs index e69de29..19a38d5 100644 --- a/farming/logics/traits/rewarder/rewarder.rs +++ b/farming/logics/traits/rewarder/rewarder.rs @@ -0,0 +1,74 @@ +pub use crate::traits::rewarder::{ + data::Data, + errors::RewarderError, + getters::RewarderGetters, +}; +use ink_env::AccountId; +use ink_prelude::vec::Vec; +use openbrush::{ + contracts::traits::psp22::PSP22Ref, + modifier_definition, + modifiers, + traits::{ + Balance, + Storage, + }, +}; + +// Cannot be 0 or it will panic! +pub const REWARD_TOKEN_DIVISOR: u128 = 1_000_000_000_000_000_000; + +#[openbrush::wrapper] +pub type RewarderRef = dyn Rewarder; + +#[openbrush::trait_definition] +pub trait Rewarder: Storage + RewarderGetters { + #[ink(message)] + #[modifiers(only_master_chef)] + fn on_arsw_reward( + &self, + _user: AccountId, + to: AccountId, + arsw_amount: Balance, + ) -> Result<(), RewarderError> { + let pending_reward = arsw_amount + .checked_mul(self.reward_multiplier().into()) + .ok_or(RewarderError::MulOverflow1)? + / REWARD_TOKEN_DIVISOR; + let reward_token = self.data::().reward_token; + let reward_bal = PSP22Ref::balance_of(&reward_token, Self::env().account_id()); + if pending_reward < reward_bal { + PSP22Ref::transfer(&reward_token, to, reward_bal, Vec::new())?; + } else { + PSP22Ref::transfer(&reward_token, to, pending_reward, Vec::new())?; + } + Ok(()) + } + + #[ink(message)] + fn pending_tokens( + &self, + _pool_id: u32, + _user: AccountId, + arsw_amount: Balance, + ) -> Result<(AccountId, Balance), RewarderError> { + let reward_amount = arsw_amount + .checked_mul(self.reward_multiplier().into()) + .ok_or(RewarderError::MulOverflow2)? + / REWARD_TOKEN_DIVISOR; + Ok((self.reward_token(), reward_amount)) + } +} + +#[modifier_definition] +pub fn only_master_chef(instance: &T, body: F) -> Result +where + T: Storage, + F: FnOnce(&T) -> Result, + E: From, +{ + if instance.data().master_chef != T::env().caller() { + return Err(From::from(RewarderError::CallerIsNotMasterChef)) + } + body(instance) +} From a10a9d26f28a70a18e99a42395805761070792e1 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 21 Oct 2022 17:38:06 +0200 Subject: [PATCH 19/36] withdraw & harvest --- .../{farming => master_chef}/Cargo.toml | 4 +- .../contracts/{farming => master_chef}/lib.rs | 2 +- farming/logics/traits/master_chef/errors.rs | 10 +++ farming/logics/traits/master_chef/farming.rs | 89 +++++++++++++++++-- 4 files changed, 94 insertions(+), 11 deletions(-) rename farming/contracts/{farming => master_chef}/Cargo.toml (95%) rename farming/contracts/{farming => master_chef}/lib.rs (97%) diff --git a/farming/contracts/farming/Cargo.toml b/farming/contracts/master_chef/Cargo.toml similarity index 95% rename from farming/contracts/farming/Cargo.toml rename to farming/contracts/master_chef/Cargo.toml index 9992ed4..37c5509 100644 --- a/farming/contracts/farming/Cargo.toml +++ b/farming/contracts/master_chef/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "farming_contract" +name = "master_chef_contract" version = "0.1.0" authors = ["Stake Technologies "] edition = "2021" @@ -19,7 +19,7 @@ openbrush = { version = "2.2.0", default-features = false, features = ["ownable" farming = { path = "../../logics", default-features = false } [lib] -name = "farming_contract" +name = "master_chef_contract" path = "lib.rs" crate-type = ["cdylib"] diff --git a/farming/contracts/farming/lib.rs b/farming/contracts/master_chef/lib.rs similarity index 97% rename from farming/contracts/farming/lib.rs rename to farming/contracts/master_chef/lib.rs index 6d17803..6c49eff 100644 --- a/farming/contracts/farming/lib.rs +++ b/farming/contracts/master_chef/lib.rs @@ -2,7 +2,7 @@ #![feature(min_specialization)] #[openbrush::contract] -pub mod farming { +pub mod master_chef_contract { use farming::traits::master_chef::{ events::*, farming::*, diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs index 55c3f21..c1fd1a4 100644 --- a/farming/logics/traits/master_chef/errors.rs +++ b/farming/logics/traits/master_chef/errors.rs @@ -16,6 +16,8 @@ pub enum FarmingError { PoolNotFound3, PoolNotFound4, PoolNotFound5, + PoolNotFound6, + PoolNotFound7, UserNotFound, ZeroWithdrawal, LpTokenNotFound, @@ -23,7 +25,10 @@ pub enum FarmingError { BlockNumberLowerThanOriginBlock, CastToi128Error, CastTou128Error1, + CastTou128Error2, CastToi128Error2, + CastToi128Error3, + CastToi128Error4, RewarderNotFound, SubUnderflow1, SubUnderflow2, @@ -32,6 +37,8 @@ pub enum FarmingError { SubUnderflow5, SubUnderflow6, SubUnderflow7, + SubUnderflow8, + SubUnderflow9, AddOverflow1, AddOverflow2, AddOverflow3, @@ -43,6 +50,7 @@ pub enum FarmingError { AddOverflow9, AddOverflow10, AddOverflow11, + AddOverflow12, MulOverflow1, MulOverflow2, MulOverflow3, @@ -53,6 +61,8 @@ pub enum FarmingError { MulOverflow8, MulOverflow9, MulOverflow10, + MulOverflow11, + MulOverflow12, PowOverflow1, PowOverflow2, DivByZero1, diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index 2dfe568..29beeb8 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -167,6 +167,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let pool = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound4)?; + self._update_pool(pool_id)?; let user = self.get_user_info(pool_id, to).unwrap_or_default(); let user_amount = user .amount @@ -222,21 +223,46 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far if amount == 0 { return Err(FarmingError::ZeroWithdrawal) } + let pool = self + .get_pool_infos(pool_id) + .ok_or(FarmingError::PoolNotFound6)?; + self._update_pool(pool_id)?; let caller = Self::env().caller(); - let user_info = self + let user = self .get_user_info(pool_id, caller) .ok_or(FarmingError::UserNotFound)?; - // TODO: Fix reward_debt + let user_reward_debt = user + .reward_debt + .checked_sub( + >::try_into( + amount + .checked_mul(pool.acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow11)? + / ACC_ARSW_PRECISION, + ) + .map_err(|_| FarmingError::CastToi128Error4)?, + ) + .ok_or(FarmingError::SubUnderflow8)?; + + let user_amount = user + .amount + .checked_sub(amount) + .ok_or(FarmingError::AddOverflow12)?; + self.data::().user_info.insert( &(pool_id, to), &UserInfo { - amount: user_info - .amount - .checked_sub(amount) - .ok_or(FarmingError::SubUnderflow2)?, - reward_debt: user_info.reward_debt, + amount: user_amount, + reward_debt: user_reward_debt, }, ); + + if let Some(rewarder_address) = self.get_rewarder(pool_id) { + if rewarder_address != ZERO_ADDRESS.into() { + RewarderRef::on_arsw_reward(&rewarder_address, caller, to, user_amount)?; + } + } + let lp_token = self .get_lp_token(pool_id) .ok_or(FarmingError::PoolNotFound3)?; @@ -245,7 +271,54 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } #[ink(message)] - fn harvest(&mut self, _pool_id: u32, _to: AccountId) -> Result<(), FarmingError> { + fn harvest(&mut self, pool_id: u32, to: AccountId) -> Result<(), FarmingError> { + let pool = self + .get_pool_infos(pool_id) + .ok_or(FarmingError::PoolNotFound7)?; + self._update_pool(pool_id)?; + let caller = Self::env().caller(); + let user = self + .get_user_info(pool_id, caller) + .ok_or(FarmingError::UserNotFound)?; + + let accumulated_arsw = >::try_into( + user.amount + .checked_mul(pool.acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow12)? + / ACC_ARSW_PRECISION, + ) + .map_err(|_| FarmingError::CastToi128Error3)?; + + let pending_arsw = >::try_into( + accumulated_arsw + .checked_sub(user.reward_debt) + .ok_or(FarmingError::SubUnderflow9)?, + ) + .map_err(|_| FarmingError::CastTou128Error2)?; + + self.data::().user_info.insert( + &(pool_id, to), + &UserInfo { + reward_debt: accumulated_arsw, + ..user + }, + ); + + if pending_arsw != 0 { + PSP22Ref::transfer( + &mut self.data::().arsw_token, + to, + pending_arsw, + Vec::new(), + )?; + } + + if let Some(rewarder_address) = self.get_rewarder(pool_id) { + if rewarder_address != ZERO_ADDRESS.into() { + RewarderRef::on_arsw_reward(&rewarder_address, caller, to, pending_arsw)?; + } + } + Ok(()) } From f1836b562ea1865c320f42472b000d0edd9624a2 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Wed, 19 Oct 2022 16:14:31 +0200 Subject: [PATCH 20/36] Finished update all pools --- farming/contracts/farming/Cargo.toml | 7 +- farming/logics/traits/farming.rs | 133 +++++++++++++++++++++++++-- 2 files changed, 133 insertions(+), 7 deletions(-) diff --git a/farming/contracts/farming/Cargo.toml b/farming/contracts/farming/Cargo.toml index 2f3d162..4473e5e 100644 --- a/farming/contracts/farming/Cargo.toml +++ b/farming/contracts/farming/Cargo.toml @@ -38,4 +38,9 @@ std = [ "openbrush/std", "farming/std" ] -ink-as-dependency = [] + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index 2384cb3..70406be 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -26,7 +26,7 @@ use openbrush::{ pub const ACC_ARSW_PRECISION: u8 = 12; pub const ARTHSWAP_ORIGIN_BLOCK: u32 = 1u32; pub const BLOCK_PER_PERIOD: u32 = 215000u32; -pub const MAX_PERIOD: u8 = 23u8; +pub const MAX_PERIOD: u32 = 23u32; pub const FIRST_PERIOD_REWERD_SUPPLY: Balance = 151629858171523000000u128; #[openbrush::trait_definition] @@ -69,7 +69,12 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } #[ink(message)] - fn pending_arsw(&self, _pool_id: u32, _user: AccountId) -> Result { + fn pending_arsw(&mut self, pool_id: u32, user: AccountId) -> Result { + let mut pool = self + .get_pool_infos(pool_id) + .ok_or(FarmingError::PoolNotFound4)?; + let mut user = self.data::().user_info.get(&(pool_id, user)); + Ok(1_000_000_000_000_000_000) } @@ -157,7 +162,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } fn _update_pool(&mut self, pool_id: u32) -> Result<(), FarmingError> { - let pool = self + let mut pool = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound1)?; let current_block = Self::env().block_number(); @@ -168,15 +173,28 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let lp_supply = PSP22Ref::balance_of(&lp_token, Self::env().account_id()); if lp_supply > 0 { let additional_acc_arsw_per_share = - self._calculate_additional_acc_arsw_per_share(pool, current_block, lp_supply)?; + self._calculate_additional_acc_arsw_per_share(&pool, current_block, lp_supply)?; + pool.acc_arsw_per_share = pool + .acc_arsw_per_share + .checked_add(additional_acc_arsw_per_share) + .ok_or(FarmingError::AddOverflow8)?; } + pool.last_reward_block = current_block; + self.data::().pool_info.insert(pool_id, &pool); + + self._emit_log_update_pool_event( + pool_id, + pool.last_reward_block, + lp_supply, + pool.acc_arsw_per_share, + ); } Ok(()) } fn _calculate_additional_acc_arsw_per_share( &mut self, - pool_info: Pool, + pool_info: &Pool, current_block: u32, lp_supply: Balance, ) -> Result { @@ -185,7 +203,60 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } let last_reward_block_period = self._get_period(pool_info.last_reward_block)?; let current_period = self._get_period(Self::env().block_number())?; - Ok(10u128) + + let mut arsw_reward: Balance = 0; + let mut last_block = pool_info.last_reward_block; + let mut period = last_reward_block_period; + while period <= current_period { + if period > MAX_PERIOD { + break + } + let total_alloc_point: u32 = self.data::().total_alloc_point; + if current_block <= self._period_max(period)? { + arsw_reward = arsw_reward + .checked_add( + (current_block as u128) + .checked_sub(last_block as u128) + .ok_or(FarmingError::SubUnderflow4)? + .checked_mul(self._arsw_per_block(period)?) + .ok_or(FarmingError::MulOverflow3)? + .checked_mul(pool_info.alloc_point as u128) + .ok_or(FarmingError::MulOverflow4)? + .into(), + ) + .ok_or(FarmingError::AddOverflow6)? + .checked_div(total_alloc_point.into()) + .ok_or(FarmingError::DivByZero1)? + } else { + arsw_reward = arsw_reward + .checked_add( + (self._period_max(period)? as u128) + .checked_sub(last_block.into()) + .ok_or(FarmingError::SubUnderflow5)? + .checked_mul(self._arsw_per_block(period)? as u128) + .ok_or(FarmingError::MulOverflow5)? + .checked_mul( + pool_info + .alloc_point + .checked_div(total_alloc_point) + .ok_or(FarmingError::DivByZero2)? + .into(), + ) + .ok_or(FarmingError::MulOverflow6)? + .into(), + ) + .ok_or(FarmingError::AddOverflow7)?; + last_block = self._period_max(period)?; + } + + period += 1; + } + + Ok(arsw_reward + .checked_mul(ACC_ARSW_PRECISION.into()) + .ok_or(FarmingError::MulOverflow8)? + .checked_div(lp_supply) + .ok_or(FarmingError::DivByZero3)?) } fn _get_period(&self, block_number: u32) -> Result { @@ -199,6 +270,34 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::SubUnderflow1)? / BLOCK_PER_PERIOD) } + + fn _period_max(&self, period: u32) -> Result { + Ok(ARTHSWAP_ORIGIN_BLOCK + .checked_add( + BLOCK_PER_PERIOD + .checked_mul(period.checked_add(1).ok_or(FarmingError::AddOverflow4)?) + .ok_or(FarmingError::MulOverflow1)?, + ) + .ok_or(FarmingError::AddOverflow5)? + .checked_sub(1) + .ok_or(FarmingError::SubUnderflow3)?) + } + + fn _arsw_per_block(&self, period: u32) -> Result { + if period > MAX_PERIOD { + return Ok(0) + } + Ok(FIRST_PERIOD_REWERD_SUPPLY + .checked_mul( + 9u128 + .checked_pow(period) + .ok_or(FarmingError::PowOverflow1)? + / 10u128 + .checked_pow(period) + .ok_or(FarmingError::PowOverflow2)?, + ) + .ok_or(FarmingError::MulOverflow2)?) + } } #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] @@ -210,6 +309,7 @@ pub enum FarmingError { PoolNotFound1, PoolNotFound2, PoolNotFound3, + PoolNotFound4, UserNotFound, ZeroWithdrawal, LpTokenNotFound, @@ -217,9 +317,30 @@ pub enum FarmingError { BlockNumberLowerThanOriginBlock, SubUnderflow1, SubUnderflow2, + SubUnderflow3, + SubUnderflow4, + SubUnderflow5, AddOverflow1, AddOverflow2, AddOverflow3, + AddOverflow4, + AddOverflow5, + AddOverflow6, + AddOverflow7, + AddOverflow8, + MulOverflow1, + MulOverflow2, + MulOverflow3, + MulOverflow4, + MulOverflow5, + MulOverflow6, + MulOverflow7, + MulOverflow8, + PowOverflow1, + PowOverflow2, + DivByZero1, + DivByZero2, + DivByZero3, } impl From for FarmingError { From fce8b4352c225911a57ea73dbc09b2dccbabd675 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Wed, 19 Oct 2022 16:49:11 +0200 Subject: [PATCH 21/36] pending arsw --- farming/logics/traits/data.rs | 14 ++++++- farming/logics/traits/farming.rs | 67 ++++++++++++++++++++++++-------- farming/logics/traits/getters.rs | 7 +++- 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/farming/logics/traits/data.rs b/farming/logics/traits/data.rs index 3dc1aa9..8ca6f19 100644 --- a/farming/logics/traits/data.rs +++ b/farming/logics/traits/data.rs @@ -3,7 +3,10 @@ use ink_storage::{ traits::*, Mapping, }; -use openbrush::traits::AccountId; +use openbrush::traits::{ + AccountId, + Balance, +}; use scale::{ Decode, Encode, @@ -19,6 +22,13 @@ pub struct Pool { pub alloc_point: u32, } +#[derive(Encode, Decode, SpreadLayout, PackedLayout, SpreadAllocate, Default)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo, StorageLayout))] +pub struct UserInfo { + pub amount: Balance, + pub reward_debt: i128, +} + #[derive(Default, Debug)] #[openbrush::upgradeable_storage(STORAGE_KEY)] pub struct Data { @@ -30,7 +40,7 @@ pub struct Data { /// Value (`amount`: u128, `reward_debt`: u128) /// `amount` LP token amount the user has provided. /// `reward_debt` The amount of ARSW entitled to the user. - pub user_info: Mapping<(u32, AccountId), (u128, i128)>, + pub user_info: Mapping<(u32, AccountId), UserInfo>, /// Info of each MasterChef pool. /// Key `pool_id`: u32 diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index 70406be..c6c27c6 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -1,3 +1,4 @@ +use crate::traits::data::UserInfo; pub use crate::traits::{ data::{ Data, @@ -41,6 +42,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far ) -> Result<(), FarmingError> { self._check_pool_duplicate(lp_token)?; self._update_all_pools()?; + self.data::().total_alloc_point = self .data::() .total_alloc_point @@ -48,6 +50,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::AddOverflow2)?; self.data::().lp_tokens.push(lp_token); let pool_length = self.pool_length(); + if let Some(rewarder_address) = rewarder { self.data::() .rewarders @@ -64,6 +67,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far self.data::().pool_info_length = pool_length .checked_add(1) .ok_or(FarmingError::AddOverflow2)?; + self._emit_log_pool_addition_event(pool_length, alloc_point, lp_token, rewarder); Ok(()) } @@ -73,9 +77,30 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let mut pool = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound4)?; - let mut user = self.data::().user_info.get(&(pool_id, user)); + let mut user_info = self + .get_user_info(pool_id, user) + .ok_or(FarmingError::UserNotFound)?; + let mut acc_arsw_per_share = pool.acc_arsw_per_share; + + let lp_supply = self._get_lp_supply(pool_id)?; + let current_block = Self::env().block_number(); + + if current_block > pool.last_reward_block && lp_supply != 0 { + let additional_acc_arsw_per_share = + self._calculate_additional_acc_arsw_per_share(&pool, current_block, lp_supply)?; + acc_arsw_per_share = acc_arsw_per_share + .checked_add(additional_acc_arsw_per_share) + .ok_or(FarmingError::AddOverflow8)?; + } - Ok(1_000_000_000_000_000_000) + let pending = (user_info + .amount + .checked_mul(acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow9)? + / ACC_ARSW_PRECISION) + .checked_sub(user_info.reward_debt) + .ok_or(FarmingError::SubUnderflow6)?; + Ok(pending) } #[ink(message)] @@ -85,16 +110,17 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far amount: Balance, to: AccountId, ) -> Result<(), FarmingError> { - let (prev_amount, prev_reward_debt) = self.get_user_info(pool_id, to).unwrap_or((0, 0)); + let user_info = self.get_user_info(pool_id, to).unwrap_or_default(); // TODO: Fix reward_debt self.data::().user_info.insert( &(pool_id, to), - &( - prev_amount + &UserInfo { + amount: user_info + .amount .checked_add(amount) .ok_or(FarmingError::AddOverflow1)?, - prev_reward_debt, - ), + reward_debt: user_info.reward_debt, + }, ); let lp_token = self .get_lp_token(pool_id) @@ -120,18 +146,19 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far return Err(FarmingError::ZeroWithdrawal) } let caller = Self::env().caller(); - let (prev_amount, prev_reward_debt) = self + let user_info = self .get_user_info(pool_id, caller) .ok_or(FarmingError::UserNotFound)?; // TODO: Fix reward_debt self.data::().user_info.insert( - &(pool_id, caller), - &( - prev_amount + &(pool_id, to), + &UserInfo { + amount: user_info + .amount .checked_sub(amount) .ok_or(FarmingError::SubUnderflow2)?, - prev_reward_debt, - ), + reward_debt: user_info.reward_debt, + }, ); let lp_token = self .get_lp_token(pool_id) @@ -167,10 +194,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::PoolNotFound1)?; let current_block = Self::env().block_number(); if current_block > pool.last_reward_block { - let lp_token = self - .get_lp_token(pool_id) - .ok_or(FarmingError::LpTokenNotFound)?; - let lp_supply = PSP22Ref::balance_of(&lp_token, Self::env().account_id()); + let lp_supply = self._get_lp_supply(pool_id)?; if lp_supply > 0 { let additional_acc_arsw_per_share = self._calculate_additional_acc_arsw_per_share(&pool, current_block, lp_supply)?; @@ -298,6 +322,13 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far ) .ok_or(FarmingError::MulOverflow2)?) } + + fn _get_lp_supply(&self, pool_id: u32) -> Result { + let lp_token = self + .get_lp_token(pool_id) + .ok_or(FarmingError::LpTokenNotFound)?; + Ok(PSP22Ref::balance_of(&lp_token, Self::env().account_id())) + } } #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] @@ -320,6 +351,7 @@ pub enum FarmingError { SubUnderflow3, SubUnderflow4, SubUnderflow5, + SubUnderflow6, AddOverflow1, AddOverflow2, AddOverflow3, @@ -336,6 +368,7 @@ pub enum FarmingError { MulOverflow6, MulOverflow7, MulOverflow8, + MulOverflow9, PowOverflow1, PowOverflow2, DivByZero1, diff --git a/farming/logics/traits/getters.rs b/farming/logics/traits/getters.rs index b8394ac..80af784 100644 --- a/farming/logics/traits/getters.rs +++ b/farming/logics/traits/getters.rs @@ -1,5 +1,8 @@ use crate::traits::{ - data::Pool, + data::{ + Pool, + UserInfo, + }, farming::Data, }; use ink_env::AccountId; @@ -18,7 +21,7 @@ pub trait FarmingGetters: Storage { } #[ink(message)] - fn get_user_info(&self, pool_id: u32, user: AccountId) -> Option<(u128, i128)> { + fn get_user_info(&self, pool_id: u32, user: AccountId) -> Option { self.data::().user_info.get(&(pool_id, user)) } From ddcaee7a71c50b64b5fd122a3e60f231e7adef52 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Wed, 19 Oct 2022 17:19:05 +0200 Subject: [PATCH 22/36] set function --- farming/logics/traits/events.rs | 4 +- farming/logics/traits/farming.rs | 71 +++++++++++++++++++++++++++----- farming/logics/traits/getters.rs | 5 +++ 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/farming/logics/traits/events.rs b/farming/logics/traits/events.rs index b199a24..48d50a1 100644 --- a/farming/logics/traits/events.rs +++ b/farming/logics/traits/events.rs @@ -53,8 +53,8 @@ pub trait FarmingEvents { fn _emit_log_set_pool_event( &self, _pool_id: u32, - _alloc_point: u128, - _rewardes: AccountId, + _alloc_point: u32, + _rewarder: AccountId, _overwrite: bool, ) { } diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index c6c27c6..fef9892 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -72,12 +72,51 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far Ok(()) } + #[ink(message)] + #[modifiers(only_owner)] + fn set( + &mut self, + pool_id: u32, + alloc_point: u32, + rewarder: AccountId, + overwrite: bool, + ) -> Result<(), FarmingError> { + self._update_all_pools()?; + let pool_info = self + .get_pool_infos(pool_id) + .ok_or(FarmingError::PoolNotFound5)?; + self.data::().total_alloc_point = self + .data::() + .total_alloc_point + .checked_sub(pool_info.alloc_point) + .ok_or(FarmingError::SubUnderflow7)? + .checked_add(alloc_point) + .ok_or(FarmingError::AddOverflow9)?; + + self.data::().pool_info.insert( + &pool_id, + &Pool { + alloc_point, + ..pool_info + }, + ); + let mut rewarder = rewarder; + if overwrite { + self.data::().rewarders.insert(&pool_id, &rewarder); + rewarder = self + .get_rewarder(pool_id) + .ok_or(FarmingError::RewarderNotFound)?; + } + self._emit_log_set_pool_event(pool_id, alloc_point, rewarder, overwrite); + Ok(()) + } + #[ink(message)] fn pending_arsw(&mut self, pool_id: u32, user: AccountId) -> Result { - let mut pool = self + let pool = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound4)?; - let mut user_info = self + let user_info = self .get_user_info(pool_id, user) .ok_or(FarmingError::UserNotFound)?; let mut acc_arsw_per_share = pool.acc_arsw_per_share; @@ -93,14 +132,20 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::AddOverflow8)?; } - let pending = (user_info - .amount - .checked_mul(acc_arsw_per_share) - .ok_or(FarmingError::MulOverflow9)? - / ACC_ARSW_PRECISION) - .checked_sub(user_info.reward_debt) - .ok_or(FarmingError::SubUnderflow6)?; - Ok(pending) + let pending = >::try_into( + user_info + .amount + .checked_mul(acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow9)? + / ACC_ARSW_PRECISION as u128, + ) + .map_err(|_| FarmingError::CastToi128Error)? + .checked_sub(user_info.reward_debt) + .ok_or(FarmingError::SubUnderflow6)?; + Ok( + >::try_into(pending) + .map_err(|_| FarmingError::CastTou128Error)?, + ) } #[ink(message)] @@ -341,17 +386,22 @@ pub enum FarmingError { PoolNotFound2, PoolNotFound3, PoolNotFound4, + PoolNotFound5, UserNotFound, ZeroWithdrawal, LpTokenNotFound, LpSupplyIsZero, BlockNumberLowerThanOriginBlock, + CastToi128Error, + CastTou128Error, + RewarderNotFound, SubUnderflow1, SubUnderflow2, SubUnderflow3, SubUnderflow4, SubUnderflow5, SubUnderflow6, + SubUnderflow7, AddOverflow1, AddOverflow2, AddOverflow3, @@ -360,6 +410,7 @@ pub enum FarmingError { AddOverflow6, AddOverflow7, AddOverflow8, + AddOverflow9, MulOverflow1, MulOverflow2, MulOverflow3, diff --git a/farming/logics/traits/getters.rs b/farming/logics/traits/getters.rs index 80af784..6ad2e10 100644 --- a/farming/logics/traits/getters.rs +++ b/farming/logics/traits/getters.rs @@ -29,4 +29,9 @@ pub trait FarmingGetters: Storage { fn get_lp_token(&self, pool_id: u32) -> Option { self.data::().lp_tokens.get(pool_id as usize).copied() } + + #[ink(message)] + fn get_rewarder(&self, pool_id: u32) -> Option { + self.data::().rewarders.get(pool_id) + } } From 8248c1f46ee7cf420bb214844253ab573f42ea2a Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Thu, 20 Oct 2022 10:43:07 +0200 Subject: [PATCH 23/36] clean code - pr comments --- farming/logics/traits/events.rs | 2 +- farming/logics/traits/farming.rs | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/farming/logics/traits/events.rs b/farming/logics/traits/events.rs index 48d50a1..939b8fd 100644 --- a/farming/logics/traits/events.rs +++ b/farming/logics/traits/events.rs @@ -54,7 +54,7 @@ pub trait FarmingEvents { &self, _pool_id: u32, _alloc_point: u32, - _rewarder: AccountId, + _rewarder: Option, _overwrite: bool, ) { } diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/farming.rs index fef9892..adc2a2e 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/farming.rs @@ -24,7 +24,7 @@ use openbrush::{ }, }; -pub const ACC_ARSW_PRECISION: u8 = 12; +pub const ACC_ARSW_PRECISION: u128 = 1_000_000_000_000; pub const ARTHSWAP_ORIGIN_BLOCK: u32 = 1u32; pub const BLOCK_PER_PERIOD: u32 = 215000u32; pub const MAX_PERIOD: u32 = 23u32; @@ -78,13 +78,13 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far &mut self, pool_id: u32, alloc_point: u32, - rewarder: AccountId, + rewarder: Option, overwrite: bool, ) -> Result<(), FarmingError> { - self._update_all_pools()?; let pool_info = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound5)?; + self._update_all_pools()?; self.data::().total_alloc_point = self .data::() .total_alloc_point @@ -102,10 +102,16 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far ); let mut rewarder = rewarder; if overwrite { - self.data::().rewarders.insert(&pool_id, &rewarder); - rewarder = self - .get_rewarder(pool_id) - .ok_or(FarmingError::RewarderNotFound)?; + match rewarder { + Some(rewarder_address) => { + self.data::() + .rewarders + .insert(&pool_id, &rewarder_address) + } + None => self.data::().rewarders.remove(&pool_id), + } + } else { + rewarder = self.get_rewarder(pool_id); } self._emit_log_set_pool_event(pool_id, alloc_point, rewarder, overwrite); Ok(()) @@ -137,7 +143,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .amount .checked_mul(acc_arsw_per_share) .ok_or(FarmingError::MulOverflow9)? - / ACC_ARSW_PRECISION as u128, + / ACC_ARSW_PRECISION, ) .map_err(|_| FarmingError::CastToi128Error)? .checked_sub(user_info.reward_debt) @@ -322,7 +328,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } Ok(arsw_reward - .checked_mul(ACC_ARSW_PRECISION.into()) + .checked_mul(ACC_ARSW_PRECISION) .ok_or(FarmingError::MulOverflow8)? .checked_div(lp_supply) .ok_or(FarmingError::DivByZero3)?) From 09e2dfeed4b4b49ce0a06789d007249c84d482bd Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Thu, 20 Oct 2022 14:51:37 +0200 Subject: [PATCH 24/36] refactor file structure --- farming/contracts/farming/lib.rs | 2 +- .../logics/traits/{ => master_chef}/data.rs | 0 farming/logics/traits/master_chef/errors.rs | 71 +++++++++++ .../logics/traits/{ => master_chef}/events.rs | 0 .../traits/{ => master_chef}/farming.rs | 120 ++++++------------ .../traits/{ => master_chef}/getters.rs | 2 +- farming/logics/traits/master_chef/mod.rs | 5 + farming/logics/traits/mod.rs | 6 +- farming/logics/traits/rewarder/mod.rs | 1 + farming/logics/traits/rewarder/rewarder.rs | 0 10 files changed, 121 insertions(+), 86 deletions(-) rename farming/logics/traits/{ => master_chef}/data.rs (100%) create mode 100644 farming/logics/traits/master_chef/errors.rs rename farming/logics/traits/{ => master_chef}/events.rs (100%) rename farming/logics/traits/{ => master_chef}/farming.rs (86%) rename farming/logics/traits/{ => master_chef}/getters.rs (96%) create mode 100644 farming/logics/traits/master_chef/mod.rs create mode 100644 farming/logics/traits/rewarder/mod.rs create mode 100644 farming/logics/traits/rewarder/rewarder.rs diff --git a/farming/contracts/farming/lib.rs b/farming/contracts/farming/lib.rs index 0436cf7..6d17803 100644 --- a/farming/contracts/farming/lib.rs +++ b/farming/contracts/farming/lib.rs @@ -3,7 +3,7 @@ #[openbrush::contract] pub mod farming { - use farming::traits::{ + use farming::traits::master_chef::{ events::*, farming::*, getters::*, diff --git a/farming/logics/traits/data.rs b/farming/logics/traits/master_chef/data.rs similarity index 100% rename from farming/logics/traits/data.rs rename to farming/logics/traits/master_chef/data.rs diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs new file mode 100644 index 0000000..aa3b002 --- /dev/null +++ b/farming/logics/traits/master_chef/errors.rs @@ -0,0 +1,71 @@ +use openbrush::contracts::{ + ownable::*, + traits::psp22::PSP22Error, +}; + +#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] +pub enum FarmingError { + OwnableError(OwnableError), + PSP22Error(PSP22Error), + DuplicateLPToken, + PoolNotFound1, + PoolNotFound2, + PoolNotFound3, + PoolNotFound4, + PoolNotFound5, + UserNotFound, + ZeroWithdrawal, + LpTokenNotFound, + LpSupplyIsZero, + BlockNumberLowerThanOriginBlock, + CastToi128Error, + CastTou128Error1, + CastToi128Error2, + RewarderNotFound, + SubUnderflow1, + SubUnderflow2, + SubUnderflow3, + SubUnderflow4, + SubUnderflow5, + SubUnderflow6, + SubUnderflow7, + AddOverflow1, + AddOverflow2, + AddOverflow3, + AddOverflow4, + AddOverflow5, + AddOverflow6, + AddOverflow7, + AddOverflow8, + AddOverflow9, + AddOverflow10, + AddOverflow11, + MulOverflow1, + MulOverflow2, + MulOverflow3, + MulOverflow4, + MulOverflow5, + MulOverflow6, + MulOverflow7, + MulOverflow8, + MulOverflow9, + MulOverflow10, + PowOverflow1, + PowOverflow2, + DivByZero1, + DivByZero2, + DivByZero3, +} + +impl From for FarmingError { + fn from(error: OwnableError) -> Self { + FarmingError::OwnableError(error) + } +} + +impl From for FarmingError { + fn from(error: PSP22Error) -> Self { + FarmingError::PSP22Error(error) + } +} diff --git a/farming/logics/traits/events.rs b/farming/logics/traits/master_chef/events.rs similarity index 100% rename from farming/logics/traits/events.rs rename to farming/logics/traits/master_chef/events.rs diff --git a/farming/logics/traits/farming.rs b/farming/logics/traits/master_chef/farming.rs similarity index 86% rename from farming/logics/traits/farming.rs rename to farming/logics/traits/master_chef/farming.rs index adc2a2e..aff9a25 100644 --- a/farming/logics/traits/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -1,5 +1,8 @@ -use crate::traits::data::UserInfo; -pub use crate::traits::{ +use crate::traits::master_chef::{ + data::UserInfo, + errors::FarmingError, +}; +pub use crate::traits::master_chef::{ data::{ Data, Pool, @@ -11,19 +14,18 @@ use ink_prelude::vec::Vec; use openbrush::{ contracts::{ ownable::*, - traits::psp22::{ - PSP22Error, - PSP22Ref, - }, + traits::psp22::PSP22Ref, }, modifiers, traits::{ AccountId, Balance, Storage, + ZERO_ADDRESS, }, }; +// Cannot be 0 or it will panic! pub const ACC_ARSW_PRECISION: u128 = 1_000_000_000_000; pub const ARTHSWAP_ORIGIN_BLOCK: u32 = 1u32; pub const BLOCK_PER_PERIOD: u32 = 215000u32; @@ -148,10 +150,8 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .map_err(|_| FarmingError::CastToi128Error)? .checked_sub(user_info.reward_debt) .ok_or(FarmingError::SubUnderflow6)?; - Ok( - >::try_into(pending) - .map_err(|_| FarmingError::CastTou128Error)?, - ) + Ok(>::try_into(pending) + .map_err(|_| FarmingError::CastTou128Error1)?) } #[ink(message)] @@ -161,18 +161,41 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far amount: Balance, to: AccountId, ) -> Result<(), FarmingError> { - let user_info = self.get_user_info(pool_id, to).unwrap_or_default(); - // TODO: Fix reward_debt + let pool = self + .get_pool_infos(pool_id) + .ok_or(FarmingError::PoolNotFound4)?; + let user = self.get_user_info(pool_id, to).unwrap_or_default(); + let user_amount = user + .amount + .checked_add(amount) + .ok_or(FarmingError::AddOverflow10)?; + let user_reward_debt = user + .reward_debt + .checked_add( + >::try_into( + amount + .checked_mul(pool.acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow10)? + / ACC_ARSW_PRECISION, + ) + .map_err(|_| FarmingError::CastToi128Error2)?, + ) + .ok_or(FarmingError::AddOverflow11)?; + self.data::().user_info.insert( &(pool_id, to), &UserInfo { - amount: user_info - .amount - .checked_add(amount) - .ok_or(FarmingError::AddOverflow1)?, - reward_debt: user_info.reward_debt, + amount: user_amount, + reward_debt: user_reward_debt, }, ); + + if let Some(rewarder_address) = self.get_rewarder(pool_id) { + if rewarder_address != ZERO_ADDRESS.into() { + // rewarder.onARSWReward(pid, to, to, 0, user.amount); + } + } + let lp_token = self .get_lp_token(pool_id) .ok_or(FarmingError::PoolNotFound2)?; @@ -381,66 +404,3 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far Ok(PSP22Ref::balance_of(&lp_token, Self::env().account_id())) } } - -#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] -#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] -pub enum FarmingError { - OwnableError(OwnableError), - PSP22Error(PSP22Error), - DuplicateLPToken, - PoolNotFound1, - PoolNotFound2, - PoolNotFound3, - PoolNotFound4, - PoolNotFound5, - UserNotFound, - ZeroWithdrawal, - LpTokenNotFound, - LpSupplyIsZero, - BlockNumberLowerThanOriginBlock, - CastToi128Error, - CastTou128Error, - RewarderNotFound, - SubUnderflow1, - SubUnderflow2, - SubUnderflow3, - SubUnderflow4, - SubUnderflow5, - SubUnderflow6, - SubUnderflow7, - AddOverflow1, - AddOverflow2, - AddOverflow3, - AddOverflow4, - AddOverflow5, - AddOverflow6, - AddOverflow7, - AddOverflow8, - AddOverflow9, - MulOverflow1, - MulOverflow2, - MulOverflow3, - MulOverflow4, - MulOverflow5, - MulOverflow6, - MulOverflow7, - MulOverflow8, - MulOverflow9, - PowOverflow1, - PowOverflow2, - DivByZero1, - DivByZero2, - DivByZero3, -} - -impl From for FarmingError { - fn from(error: OwnableError) -> Self { - FarmingError::OwnableError(error) - } -} - -impl From for FarmingError { - fn from(error: PSP22Error) -> Self { - FarmingError::PSP22Error(error) - } -} diff --git a/farming/logics/traits/getters.rs b/farming/logics/traits/master_chef/getters.rs similarity index 96% rename from farming/logics/traits/getters.rs rename to farming/logics/traits/master_chef/getters.rs index 6ad2e10..583e3a5 100644 --- a/farming/logics/traits/getters.rs +++ b/farming/logics/traits/master_chef/getters.rs @@ -1,4 +1,4 @@ -use crate::traits::{ +use crate::traits::master_chef::{ data::{ Pool, UserInfo, diff --git a/farming/logics/traits/master_chef/mod.rs b/farming/logics/traits/master_chef/mod.rs new file mode 100644 index 0000000..38029af --- /dev/null +++ b/farming/logics/traits/master_chef/mod.rs @@ -0,0 +1,5 @@ +pub mod data; +pub mod errors; +pub mod events; +pub mod farming; +pub mod getters; diff --git a/farming/logics/traits/mod.rs b/farming/logics/traits/mod.rs index 321934a..207f3e2 100644 --- a/farming/logics/traits/mod.rs +++ b/farming/logics/traits/mod.rs @@ -1,4 +1,2 @@ -pub mod data; -pub mod events; -pub mod farming; -pub mod getters; +pub mod master_chef; +pub mod rewarder; diff --git a/farming/logics/traits/rewarder/mod.rs b/farming/logics/traits/rewarder/mod.rs new file mode 100644 index 0000000..5776dfc --- /dev/null +++ b/farming/logics/traits/rewarder/mod.rs @@ -0,0 +1 @@ +pub mod rewarder; diff --git a/farming/logics/traits/rewarder/rewarder.rs b/farming/logics/traits/rewarder/rewarder.rs new file mode 100644 index 0000000..e69de29 From d2e407c6c0956d7cf9df7a2669ce63cf52a1bbd3 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 21 Oct 2022 11:24:55 +0200 Subject: [PATCH 25/36] Impl rewarder --- farming/contracts/rewarder/Cargo.toml | 45 ++++++++++++ farming/contracts/rewarder/lib.rs | 42 +++++++++++ farming/logics/traits/master_chef/errors.rs | 8 +++ farming/logics/traits/master_chef/farming.rs | 17 +++-- farming/logics/traits/rewarder/data.rs | 11 +++ farming/logics/traits/rewarder/errors.rs | 16 +++++ farming/logics/traits/rewarder/getters.rs | 21 ++++++ farming/logics/traits/rewarder/mod.rs | 3 + farming/logics/traits/rewarder/rewarder.rs | 74 ++++++++++++++++++++ 9 files changed, 230 insertions(+), 7 deletions(-) create mode 100644 farming/contracts/rewarder/Cargo.toml create mode 100644 farming/contracts/rewarder/lib.rs create mode 100644 farming/logics/traits/rewarder/data.rs create mode 100644 farming/logics/traits/rewarder/errors.rs create mode 100644 farming/logics/traits/rewarder/getters.rs diff --git a/farming/contracts/rewarder/Cargo.toml b/farming/contracts/rewarder/Cargo.toml new file mode 100644 index 0000000..66fea6e --- /dev/null +++ b/farming/contracts/rewarder/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "rewarder_contract" +version = "0.1.0" +authors = ["Stake Technologies "] +edition = "2021" + +[dependencies] +ink_primitives = { version = "~3.3.0", default-features = false } +ink_metadata = { version = "~3.3.0", default-features = false, features = ["derive"], optional = true } +ink_env = { version = "~3.3.0", default-features = false } +ink_storage = { version = "~3.3.0", default-features = false } +ink_lang = { version = "~3.3.0", default-features = false } +ink_prelude = { version = "~3.3.0", default-features = false } + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } + +openbrush = { version = "2.2.0", default-features = false, features = ["psp22"] } +farming = { path = "../../logics", default-features = false } + +[lib] +name = "rewarder_contract" +path = "lib.rs" +crate-type = ["cdylib"] + +[features] +default = ["std"] +std = [ + "ink_primitives/std", + "ink_metadata", + "ink_metadata/std", + "ink_env/std", + "ink_storage/std", + "ink_lang/std", + "scale/std", + "scale-info", + "scale-info/std", + "openbrush/std", + "farming/std" +] +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false diff --git a/farming/contracts/rewarder/lib.rs b/farming/contracts/rewarder/lib.rs new file mode 100644 index 0000000..882db94 --- /dev/null +++ b/farming/contracts/rewarder/lib.rs @@ -0,0 +1,42 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![feature(min_specialization)] + +#[openbrush::contract] +pub mod rewarder { + use farming::traits::rewarder::{ + data::*, + getters::*, + rewarder::*, + }; + use ink_storage::traits::SpreadAllocate; + use openbrush::traits::Storage; + + #[ink(storage)] + #[derive(Default, SpreadAllocate, Storage)] + pub struct Rewarderontract { + #[storage_field] + rewarder: Data, + } + + impl Rewarder for Rewarderontract {} + + impl RewarderGetters for Rewarderontract {} + + impl Rewarderontract { + #[ink(constructor)] + pub fn new( + reward_multiplier: u32, + reward_token: AccountId, + master_chef: AccountId, + ) -> Self { + ink_lang::codegen::initialize_contract(|instance: &mut Self| { + instance.rewarder.reward_multiplier = reward_multiplier; + instance.rewarder.reward_token = reward_token; + instance.rewarder.master_chef = master_chef; + }) + } + + #[ink(message)] + pub fn dummy(&self) {} + } +} diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs index aa3b002..55c3f21 100644 --- a/farming/logics/traits/master_chef/errors.rs +++ b/farming/logics/traits/master_chef/errors.rs @@ -1,3 +1,4 @@ +use crate::traits::rewarder::errors::RewarderError; use openbrush::contracts::{ ownable::*, traits::psp22::PSP22Error, @@ -8,6 +9,7 @@ use openbrush::contracts::{ pub enum FarmingError { OwnableError(OwnableError), PSP22Error(PSP22Error), + RewarderError(RewarderError), DuplicateLPToken, PoolNotFound1, PoolNotFound2, @@ -69,3 +71,9 @@ impl From for FarmingError { FarmingError::PSP22Error(error) } } + +impl From for FarmingError { + fn from(error: RewarderError) -> Self { + FarmingError::RewarderError(error) + } +} diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index aff9a25..456af3d 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -2,13 +2,16 @@ use crate::traits::master_chef::{ data::UserInfo, errors::FarmingError, }; -pub use crate::traits::master_chef::{ - data::{ - Data, - Pool, +pub use crate::traits::{ + master_chef::{ + data::{ + Data, + Pool, + }, + events::FarmingEvents, + getters::FarmingGetters, }, - events::FarmingEvents, - getters::FarmingGetters, + rewarder::rewarder::RewarderRef, }; use ink_prelude::vec::Vec; use openbrush::{ @@ -192,7 +195,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far if let Some(rewarder_address) = self.get_rewarder(pool_id) { if rewarder_address != ZERO_ADDRESS.into() { - // rewarder.onARSWReward(pid, to, to, 0, user.amount); + RewarderRef::on_arsw_reward(&rewarder_address, to, to, user_amount)?; } } diff --git a/farming/logics/traits/rewarder/data.rs b/farming/logics/traits/rewarder/data.rs new file mode 100644 index 0000000..55fcc4a --- /dev/null +++ b/farming/logics/traits/rewarder/data.rs @@ -0,0 +1,11 @@ +use ink_env::AccountId; + +pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data); + +#[derive(Default, Debug)] +#[openbrush::upgradeable_storage(STORAGE_KEY)] +pub struct Data { + pub reward_multiplier: u32, + pub reward_token: AccountId, + pub master_chef: AccountId, +} diff --git a/farming/logics/traits/rewarder/errors.rs b/farming/logics/traits/rewarder/errors.rs new file mode 100644 index 0000000..8942614 --- /dev/null +++ b/farming/logics/traits/rewarder/errors.rs @@ -0,0 +1,16 @@ +use openbrush::contracts::traits::psp22::PSP22Error; + +#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] +#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] +pub enum RewarderError { + PSP22Error(PSP22Error), + CallerIsNotMasterChef, + MulOverflow1, + MulOverflow2, +} + +impl From for RewarderError { + fn from(error: PSP22Error) -> Self { + RewarderError::PSP22Error(error) + } +} diff --git a/farming/logics/traits/rewarder/getters.rs b/farming/logics/traits/rewarder/getters.rs new file mode 100644 index 0000000..c358ed5 --- /dev/null +++ b/farming/logics/traits/rewarder/getters.rs @@ -0,0 +1,21 @@ +use crate::traits::rewarder::rewarder::Data; +use ink_env::AccountId; +use openbrush::traits::Storage; + +#[openbrush::trait_definition] +pub trait RewarderGetters: Storage { + #[ink(message)] + fn reward_multiplier(&self) -> u32 { + self.data::().reward_multiplier + } + + #[ink(message)] + fn reward_token(&self) -> AccountId { + self.data::().reward_token + } + + #[ink(message)] + fn master_chef(&self) -> AccountId { + self.data::().master_chef + } +} diff --git a/farming/logics/traits/rewarder/mod.rs b/farming/logics/traits/rewarder/mod.rs index 5776dfc..38b2235 100644 --- a/farming/logics/traits/rewarder/mod.rs +++ b/farming/logics/traits/rewarder/mod.rs @@ -1 +1,4 @@ +pub mod data; +pub mod errors; +pub mod getters; pub mod rewarder; diff --git a/farming/logics/traits/rewarder/rewarder.rs b/farming/logics/traits/rewarder/rewarder.rs index e69de29..19a38d5 100644 --- a/farming/logics/traits/rewarder/rewarder.rs +++ b/farming/logics/traits/rewarder/rewarder.rs @@ -0,0 +1,74 @@ +pub use crate::traits::rewarder::{ + data::Data, + errors::RewarderError, + getters::RewarderGetters, +}; +use ink_env::AccountId; +use ink_prelude::vec::Vec; +use openbrush::{ + contracts::traits::psp22::PSP22Ref, + modifier_definition, + modifiers, + traits::{ + Balance, + Storage, + }, +}; + +// Cannot be 0 or it will panic! +pub const REWARD_TOKEN_DIVISOR: u128 = 1_000_000_000_000_000_000; + +#[openbrush::wrapper] +pub type RewarderRef = dyn Rewarder; + +#[openbrush::trait_definition] +pub trait Rewarder: Storage + RewarderGetters { + #[ink(message)] + #[modifiers(only_master_chef)] + fn on_arsw_reward( + &self, + _user: AccountId, + to: AccountId, + arsw_amount: Balance, + ) -> Result<(), RewarderError> { + let pending_reward = arsw_amount + .checked_mul(self.reward_multiplier().into()) + .ok_or(RewarderError::MulOverflow1)? + / REWARD_TOKEN_DIVISOR; + let reward_token = self.data::().reward_token; + let reward_bal = PSP22Ref::balance_of(&reward_token, Self::env().account_id()); + if pending_reward < reward_bal { + PSP22Ref::transfer(&reward_token, to, reward_bal, Vec::new())?; + } else { + PSP22Ref::transfer(&reward_token, to, pending_reward, Vec::new())?; + } + Ok(()) + } + + #[ink(message)] + fn pending_tokens( + &self, + _pool_id: u32, + _user: AccountId, + arsw_amount: Balance, + ) -> Result<(AccountId, Balance), RewarderError> { + let reward_amount = arsw_amount + .checked_mul(self.reward_multiplier().into()) + .ok_or(RewarderError::MulOverflow2)? + / REWARD_TOKEN_DIVISOR; + Ok((self.reward_token(), reward_amount)) + } +} + +#[modifier_definition] +pub fn only_master_chef(instance: &T, body: F) -> Result +where + T: Storage, + F: FnOnce(&T) -> Result, + E: From, +{ + if instance.data().master_chef != T::env().caller() { + return Err(From::from(RewarderError::CallerIsNotMasterChef)) + } + body(instance) +} From 79bbc70ec2fd7aaf007f2c915a235b369a9d60e2 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 21 Oct 2022 17:38:06 +0200 Subject: [PATCH 26/36] withdraw & harvest --- .../{farming => master_chef}/Cargo.toml | 4 +- .../contracts/{farming => master_chef}/lib.rs | 2 +- farming/logics/traits/master_chef/errors.rs | 10 +++ farming/logics/traits/master_chef/farming.rs | 89 +++++++++++++++++-- 4 files changed, 94 insertions(+), 11 deletions(-) rename farming/contracts/{farming => master_chef}/Cargo.toml (95%) rename farming/contracts/{farming => master_chef}/lib.rs (97%) diff --git a/farming/contracts/farming/Cargo.toml b/farming/contracts/master_chef/Cargo.toml similarity index 95% rename from farming/contracts/farming/Cargo.toml rename to farming/contracts/master_chef/Cargo.toml index 4473e5e..3c72bfd 100644 --- a/farming/contracts/farming/Cargo.toml +++ b/farming/contracts/master_chef/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "farming_contract" +name = "master_chef_contract" version = "0.1.0" authors = ["Stake Technologies "] edition = "2021" @@ -19,7 +19,7 @@ openbrush = { version = "2.2.0", default-features = false, features = ["ownable" farming = { path = "../../logics", default-features = false } [lib] -name = "farming_contract" +name = "master_chef_contract" path = "lib.rs" crate-type = ["cdylib"] diff --git a/farming/contracts/farming/lib.rs b/farming/contracts/master_chef/lib.rs similarity index 97% rename from farming/contracts/farming/lib.rs rename to farming/contracts/master_chef/lib.rs index 6d17803..6c49eff 100644 --- a/farming/contracts/farming/lib.rs +++ b/farming/contracts/master_chef/lib.rs @@ -2,7 +2,7 @@ #![feature(min_specialization)] #[openbrush::contract] -pub mod farming { +pub mod master_chef_contract { use farming::traits::master_chef::{ events::*, farming::*, diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs index 55c3f21..c1fd1a4 100644 --- a/farming/logics/traits/master_chef/errors.rs +++ b/farming/logics/traits/master_chef/errors.rs @@ -16,6 +16,8 @@ pub enum FarmingError { PoolNotFound3, PoolNotFound4, PoolNotFound5, + PoolNotFound6, + PoolNotFound7, UserNotFound, ZeroWithdrawal, LpTokenNotFound, @@ -23,7 +25,10 @@ pub enum FarmingError { BlockNumberLowerThanOriginBlock, CastToi128Error, CastTou128Error1, + CastTou128Error2, CastToi128Error2, + CastToi128Error3, + CastToi128Error4, RewarderNotFound, SubUnderflow1, SubUnderflow2, @@ -32,6 +37,8 @@ pub enum FarmingError { SubUnderflow5, SubUnderflow6, SubUnderflow7, + SubUnderflow8, + SubUnderflow9, AddOverflow1, AddOverflow2, AddOverflow3, @@ -43,6 +50,7 @@ pub enum FarmingError { AddOverflow9, AddOverflow10, AddOverflow11, + AddOverflow12, MulOverflow1, MulOverflow2, MulOverflow3, @@ -53,6 +61,8 @@ pub enum FarmingError { MulOverflow8, MulOverflow9, MulOverflow10, + MulOverflow11, + MulOverflow12, PowOverflow1, PowOverflow2, DivByZero1, diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index 456af3d..ccd2f7d 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -167,6 +167,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let pool = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound4)?; + self._update_pool(pool_id)?; let user = self.get_user_info(pool_id, to).unwrap_or_default(); let user_amount = user .amount @@ -222,21 +223,46 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far if amount == 0 { return Err(FarmingError::ZeroWithdrawal) } + let pool = self + .get_pool_infos(pool_id) + .ok_or(FarmingError::PoolNotFound6)?; + self._update_pool(pool_id)?; let caller = Self::env().caller(); - let user_info = self + let user = self .get_user_info(pool_id, caller) .ok_or(FarmingError::UserNotFound)?; - // TODO: Fix reward_debt + let user_reward_debt = user + .reward_debt + .checked_sub( + >::try_into( + amount + .checked_mul(pool.acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow11)? + / ACC_ARSW_PRECISION, + ) + .map_err(|_| FarmingError::CastToi128Error4)?, + ) + .ok_or(FarmingError::SubUnderflow8)?; + + let user_amount = user + .amount + .checked_sub(amount) + .ok_or(FarmingError::AddOverflow12)?; + self.data::().user_info.insert( &(pool_id, to), &UserInfo { - amount: user_info - .amount - .checked_sub(amount) - .ok_or(FarmingError::SubUnderflow2)?, - reward_debt: user_info.reward_debt, + amount: user_amount, + reward_debt: user_reward_debt, }, ); + + if let Some(rewarder_address) = self.get_rewarder(pool_id) { + if rewarder_address != ZERO_ADDRESS.into() { + RewarderRef::on_arsw_reward(&rewarder_address, caller, to, user_amount)?; + } + } + let lp_token = self .get_lp_token(pool_id) .ok_or(FarmingError::PoolNotFound3)?; @@ -245,7 +271,54 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } #[ink(message)] - fn harvest(&mut self, _pool_id: u32, _to: AccountId) -> Result<(), FarmingError> { + fn harvest(&mut self, pool_id: u32, to: AccountId) -> Result<(), FarmingError> { + let pool = self + .get_pool_infos(pool_id) + .ok_or(FarmingError::PoolNotFound7)?; + self._update_pool(pool_id)?; + let caller = Self::env().caller(); + let user = self + .get_user_info(pool_id, caller) + .ok_or(FarmingError::UserNotFound)?; + + let accumulated_arsw = >::try_into( + user.amount + .checked_mul(pool.acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow12)? + / ACC_ARSW_PRECISION, + ) + .map_err(|_| FarmingError::CastToi128Error3)?; + + let pending_arsw = >::try_into( + accumulated_arsw + .checked_sub(user.reward_debt) + .ok_or(FarmingError::SubUnderflow9)?, + ) + .map_err(|_| FarmingError::CastTou128Error2)?; + + self.data::().user_info.insert( + &(pool_id, to), + &UserInfo { + reward_debt: accumulated_arsw, + ..user + }, + ); + + if pending_arsw != 0 { + PSP22Ref::transfer( + &mut self.data::().arsw_token, + to, + pending_arsw, + Vec::new(), + )?; + } + + if let Some(rewarder_address) = self.get_rewarder(pool_id) { + if rewarder_address != ZERO_ADDRESS.into() { + RewarderRef::on_arsw_reward(&rewarder_address, caller, to, pending_arsw)?; + } + } + Ok(()) } From 3f6c0fa82e9e1f05c0be9cace51369ebe9912918 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Thu, 27 Oct 2022 11:46:32 +0200 Subject: [PATCH 27/36] Pr comments --- farming/contracts/master_chef/Cargo.toml | 7 +- farming/logics/Cargo.toml | 2 + farming/logics/helpers/math.rs | 5 + farming/logics/helpers/mod.rs | 1 + farming/logics/lib.rs | 1 + farming/logics/traits/master_chef/errors.rs | 4 +- farming/logics/traits/master_chef/events.rs | 9 +- farming/logics/traits/master_chef/farming.rs | 108 ++++++++++--------- farming/logics/traits/master_chef/getters.rs | 5 + farming/logics/traits/rewarder/rewarder.rs | 2 + 10 files changed, 81 insertions(+), 63 deletions(-) create mode 100644 farming/logics/helpers/math.rs create mode 100644 farming/logics/helpers/mod.rs diff --git a/farming/contracts/master_chef/Cargo.toml b/farming/contracts/master_chef/Cargo.toml index b4a7eec..3c72bfd 100644 --- a/farming/contracts/master_chef/Cargo.toml +++ b/farming/contracts/master_chef/Cargo.toml @@ -38,4 +38,9 @@ std = [ "openbrush/std", "farming/std" ] -ink-as-dependency = [] + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false diff --git a/farming/logics/Cargo.toml b/farming/logics/Cargo.toml index 7f1eeaf..17e24cf 100644 --- a/farming/logics/Cargo.toml +++ b/farming/logics/Cargo.toml @@ -15,6 +15,7 @@ ink_prelude = { version = "~3.3.0", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } +primitive-types = { version = "0.11.1", default-features = false, features = ["codec"] } openbrush = { version = "2.2.0", default-features = false, features = ["ownable"] } [lib] @@ -37,4 +38,5 @@ std = [ "scale-info", "scale-info/std", "openbrush/std", + "primitive-types/std" ] diff --git a/farming/logics/helpers/math.rs b/farming/logics/helpers/math.rs new file mode 100644 index 0000000..7874c8c --- /dev/null +++ b/farming/logics/helpers/math.rs @@ -0,0 +1,5 @@ +use primitive_types::U256; + +pub fn casted_mul(a: u128, b: u128) -> U256 { + U256::from(a) * U256::from(b) +} diff --git a/farming/logics/helpers/mod.rs b/farming/logics/helpers/mod.rs new file mode 100644 index 0000000..b8135c3 --- /dev/null +++ b/farming/logics/helpers/mod.rs @@ -0,0 +1 @@ +pub mod math; diff --git a/farming/logics/lib.rs b/farming/logics/lib.rs index 1b54fff..ccb765d 100644 --- a/farming/logics/lib.rs +++ b/farming/logics/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] #![feature(min_specialization)] +pub mod helpers; pub mod traits; diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs index c1fd1a4..a92d51f 100644 --- a/farming/logics/traits/master_chef/errors.rs +++ b/farming/logics/traits/master_chef/errors.rs @@ -23,9 +23,11 @@ pub enum FarmingError { LpTokenNotFound, LpSupplyIsZero, BlockNumberLowerThanOriginBlock, - CastToi128Error, CastTou128Error1, CastTou128Error2, + CastTou128Error3, + CastTou128Error4, + CastToi128Error, CastToi128Error2, CastToi128Error3, CastToi128Error4, diff --git a/farming/logics/traits/master_chef/events.rs b/farming/logics/traits/master_chef/events.rs index 939b8fd..beaba93 100644 --- a/farming/logics/traits/master_chef/events.rs +++ b/farming/logics/traits/master_chef/events.rs @@ -32,14 +32,7 @@ pub trait FarmingEvents { ) { } - fn _emit_harvest_event( - &self, - _user: AccountId, - _pool_id: u32, - _amount: Balance, - _to: AccountId, - ) { - } + fn _emit_harvest_event(&self, _user: AccountId, _pool_id: u32, _amount: Balance) {} fn _emit_log_pool_addition_event( &self, diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index ccd2f7d..e09ea70 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -1,7 +1,3 @@ -use crate::traits::master_chef::{ - data::UserInfo, - errors::FarmingError, -}; pub use crate::traits::{ master_chef::{ data::{ @@ -13,6 +9,13 @@ pub use crate::traits::{ }, rewarder::rewarder::RewarderRef, }; +use crate::{ + helpers::math::casted_mul, + traits::master_chef::{ + data::UserInfo, + errors::FarmingError, + }, +}; use ink_prelude::vec::Vec; use openbrush::{ contracts::{ @@ -24,9 +27,9 @@ use openbrush::{ AccountId, Balance, Storage, - ZERO_ADDRESS, }, }; +use primitive_types::U256; // Cannot be 0 or it will panic! pub const ACC_ARSW_PRECISION: u128 = 1_000_000_000_000; @@ -123,7 +126,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } #[ink(message)] - fn pending_arsw(&mut self, pool_id: u32, user: AccountId) -> Result { + fn pending_arsw(&self, pool_id: u32, user: AccountId) -> Result { let pool = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound4)?; @@ -176,11 +179,8 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let user_reward_debt = user .reward_debt .checked_add( - >::try_into( - amount - .checked_mul(pool.acc_arsw_per_share) - .ok_or(FarmingError::MulOverflow10)? - / ACC_ARSW_PRECISION, + >::try_into( + casted_mul(amount, pool.acc_arsw_per_share) / ACC_ARSW_PRECISION, ) .map_err(|_| FarmingError::CastToi128Error2)?, ) @@ -195,9 +195,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far ); if let Some(rewarder_address) = self.get_rewarder(pool_id) { - if rewarder_address != ZERO_ADDRESS.into() { - RewarderRef::on_arsw_reward(&rewarder_address, to, to, user_amount)?; - } + RewarderRef::on_arsw_reward(&rewarder_address, pool_id, to, to, 0, user_amount)?; } let lp_token = self @@ -210,6 +208,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far amount, Vec::new(), )?; + self._emit_deposit_event(Self::env().caller(), pool_id, amount, to); Ok(()) } @@ -234,11 +233,8 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let user_reward_debt = user .reward_debt .checked_sub( - >::try_into( - amount - .checked_mul(pool.acc_arsw_per_share) - .ok_or(FarmingError::MulOverflow11)? - / ACC_ARSW_PRECISION, + >::try_into( + casted_mul(amount, pool.acc_arsw_per_share) / ACC_ARSW_PRECISION, ) .map_err(|_| FarmingError::CastToi128Error4)?, ) @@ -258,15 +254,14 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far ); if let Some(rewarder_address) = self.get_rewarder(pool_id) { - if rewarder_address != ZERO_ADDRESS.into() { - RewarderRef::on_arsw_reward(&rewarder_address, caller, to, user_amount)?; - } + RewarderRef::on_arsw_reward(&rewarder_address, pool_id, caller, to, 0, user_amount)?; } let lp_token = self .get_lp_token(pool_id) .ok_or(FarmingError::PoolNotFound3)?; PSP22Ref::transfer(&lp_token, to, amount, Vec::new())?; + self._emit_withdraw_event(caller, pool_id, amount, to); Ok(()) } @@ -314,11 +309,17 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } if let Some(rewarder_address) = self.get_rewarder(pool_id) { - if rewarder_address != ZERO_ADDRESS.into() { - RewarderRef::on_arsw_reward(&rewarder_address, caller, to, pending_arsw)?; - } + RewarderRef::on_arsw_reward( + &rewarder_address, + pool_id, + caller, + to, + pending_arsw, + user.amount, + )?; } + self._emit_harvest_event(caller, pool_id, pending_arsw); Ok(()) } @@ -367,7 +368,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } fn _calculate_additional_acc_arsw_per_share( - &mut self, + &self, pool_info: &Pool, current_block: u32, lp_supply: Balance, @@ -389,37 +390,39 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far if current_block <= self._period_max(period)? { arsw_reward = arsw_reward .checked_add( - (current_block as u128) - .checked_sub(last_block as u128) - .ok_or(FarmingError::SubUnderflow4)? - .checked_mul(self._arsw_per_block(period)?) - .ok_or(FarmingError::MulOverflow3)? - .checked_mul(pool_info.alloc_point as u128) - .ok_or(FarmingError::MulOverflow4)? - .into(), + casted_mul( + (current_block + .checked_sub(last_block) + .ok_or(FarmingError::SubUnderflow4)? + as u128) + .checked_add(pool_info.alloc_point as u128) + .ok_or(FarmingError::MulOverflow4)?, + self._arsw_per_block(period)?, + ) + .checked_div(total_alloc_point.into()) + .ok_or(FarmingError::DivByZero1)? + .try_into() + .map_err(|_| FarmingError::CastTou128Error1)?, ) - .ok_or(FarmingError::AddOverflow6)? - .checked_div(total_alloc_point.into()) - .ok_or(FarmingError::DivByZero1)? + .ok_or(FarmingError::AddOverflow6)?; } else { arsw_reward = arsw_reward .checked_add( - (self._period_max(period)? as u128) - .checked_sub(last_block.into()) - .ok_or(FarmingError::SubUnderflow5)? - .checked_mul(self._arsw_per_block(period)? as u128) - .ok_or(FarmingError::MulOverflow5)? - .checked_mul( - pool_info - .alloc_point - .checked_div(total_alloc_point) - .ok_or(FarmingError::DivByZero2)? - .into(), - ) - .ok_or(FarmingError::MulOverflow6)? - .into(), + casted_mul( + (self._period_max(period)? as u128) + .checked_sub(last_block.into()) + .ok_or(FarmingError::SubUnderflow5)? + .checked_mul(pool_info.alloc_point.into()) + .ok_or(FarmingError::MulOverflow6)?, + self._arsw_per_block(period)? as u128, + ) + .checked_div(total_alloc_point.into()) + .ok_or(FarmingError::DivByZero2)? + .try_into() + .map_err(|_| FarmingError::CastTou128Error3)?, ) .ok_or(FarmingError::AddOverflow7)?; + last_block = self._period_max(period)?; } @@ -453,8 +456,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::MulOverflow1)?, ) .ok_or(FarmingError::AddOverflow5)? - .checked_sub(1) - .ok_or(FarmingError::SubUnderflow3)?) + - 1) } fn _arsw_per_block(&self, period: u32) -> Result { diff --git a/farming/logics/traits/master_chef/getters.rs b/farming/logics/traits/master_chef/getters.rs index 583e3a5..59bafa3 100644 --- a/farming/logics/traits/master_chef/getters.rs +++ b/farming/logics/traits/master_chef/getters.rs @@ -34,4 +34,9 @@ pub trait FarmingGetters: Storage { fn get_rewarder(&self, pool_id: u32) -> Option { self.data::().rewarders.get(pool_id) } + + #[ink(message)] + fn get_total_alloc_point(&self) -> u32 { + self.data::().total_alloc_point + } } diff --git a/farming/logics/traits/rewarder/rewarder.rs b/farming/logics/traits/rewarder/rewarder.rs index 19a38d5..946b747 100644 --- a/farming/logics/traits/rewarder/rewarder.rs +++ b/farming/logics/traits/rewarder/rewarder.rs @@ -27,9 +27,11 @@ pub trait Rewarder: Storage + RewarderGetters { #[modifiers(only_master_chef)] fn on_arsw_reward( &self, + _pool_id: u32, _user: AccountId, to: AccountId, arsw_amount: Balance, + _new_lp_amount: Balance, ) -> Result<(), RewarderError> { let pending_reward = arsw_amount .checked_mul(self.reward_multiplier().into()) From 801cf5c8beb9113375fbb05ea1d959d8c18ae473 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Thu, 27 Oct 2022 11:53:13 +0200 Subject: [PATCH 28/36] Pr comments --- farming/logics/traits/master_chef/errors.rs | 2 ++ farming/logics/traits/master_chef/farming.rs | 30 ++++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs index a92d51f..fba6a46 100644 --- a/farming/logics/traits/master_chef/errors.rs +++ b/farming/logics/traits/master_chef/errors.rs @@ -27,6 +27,8 @@ pub enum FarmingError { CastTou128Error2, CastTou128Error3, CastTou128Error4, + CastTou128Error5, + CastTou128Error6, CastToi128Error, CastToi128Error2, CastToi128Error3, diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index e09ea70..0b1f2b6 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -428,12 +428,11 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far period += 1; } - - Ok(arsw_reward - .checked_mul(ACC_ARSW_PRECISION) - .ok_or(FarmingError::MulOverflow8)? - .checked_div(lp_supply) - .ok_or(FarmingError::DivByZero3)?) + Ok(casted_mul(arsw_reward, ACC_ARSW_PRECISION) + .checked_div(lp_supply.into()) + .ok_or(FarmingError::DivByZero3)? + .try_into() + .map_err(|_| FarmingError::CastTou128Error6)?) } fn _get_period(&self, block_number: u32) -> Result { @@ -463,16 +462,17 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far if period > MAX_PERIOD { return Ok(0) } - Ok(FIRST_PERIOD_REWERD_SUPPLY - .checked_mul( - 9u128 + Ok(casted_mul( + FIRST_PERIOD_REWERD_SUPPLY, + 9u128 + .checked_pow(period) + .ok_or(FarmingError::PowOverflow1)? + / 10u128 .checked_pow(period) - .ok_or(FarmingError::PowOverflow1)? - / 10u128 - .checked_pow(period) - .ok_or(FarmingError::PowOverflow2)?, - ) - .ok_or(FarmingError::MulOverflow2)?) + .ok_or(FarmingError::PowOverflow2)?, + ) + .try_into() + .map_err(|_| FarmingError::CastTou128Error5)?) } fn _get_lp_supply(&self, pool_id: u32) -> Result { From c5c7232d3b8ae033641a6c4e90b0eb3e2b58b358 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Thu, 27 Oct 2022 14:58:43 +0200 Subject: [PATCH 29/36] Pr comments --- farming/logics/traits/master_chef/errors.rs | 1 + farming/logics/traits/master_chef/farming.rs | 43 ++++++++------------ 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs index fba6a46..6571988 100644 --- a/farming/logics/traits/master_chef/errors.rs +++ b/farming/logics/traits/master_chef/errors.rs @@ -33,6 +33,7 @@ pub enum FarmingError { CastToi128Error2, CastToi128Error3, CastToi128Error4, + CastToi128Error5, RewarderNotFound, SubUnderflow1, SubUnderflow2, diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index 0b1f2b6..e71b3fe 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -146,18 +146,14 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::AddOverflow8)?; } - let pending = >::try_into( - user_info - .amount - .checked_mul(acc_arsw_per_share) - .ok_or(FarmingError::MulOverflow9)? - / ACC_ARSW_PRECISION, - ) - .map_err(|_| FarmingError::CastToi128Error)? - .checked_sub(user_info.reward_debt) - .ok_or(FarmingError::SubUnderflow6)?; - Ok(>::try_into(pending) - .map_err(|_| FarmingError::CastTou128Error1)?) + let pending = (user_info + .amount + .checked_mul(acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow9)? + / ACC_ARSW_PRECISION) + .wrapping_add(user_info.reward_debt as u128); + + Ok(pending) } #[ink(message)] @@ -276,25 +272,20 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .get_user_info(pool_id, caller) .ok_or(FarmingError::UserNotFound)?; - let accumulated_arsw = >::try_into( - user.amount - .checked_mul(pool.acc_arsw_per_share) - .ok_or(FarmingError::MulOverflow12)? - / ACC_ARSW_PRECISION, - ) - .map_err(|_| FarmingError::CastToi128Error3)?; + let accumulated_arsw = user + .amount + .checked_mul(pool.acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow12)? + / ACC_ARSW_PRECISION; - let pending_arsw = >::try_into( - accumulated_arsw - .checked_sub(user.reward_debt) - .ok_or(FarmingError::SubUnderflow9)?, - ) - .map_err(|_| FarmingError::CastTou128Error2)?; + let pending_arsw = accumulated_arsw.wrapping_add(user.reward_debt as u128); self.data::().user_info.insert( &(pool_id, to), &UserInfo { - reward_debt: accumulated_arsw, + reward_debt: accumulated_arsw + .try_into() + .map_err(|_| FarmingError::CastToi128Error5)?, ..user }, ); From 5a8223d13b5f00504fc158427754c13ddb9dcf54 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 28 Oct 2022 14:38:59 +0200 Subject: [PATCH 30/36] Pr comments --- farming/logics/lib.rs | 1 + farming/logics/traits/master_chef/errors.rs | 2 ++ farming/logics/traits/master_chef/farming.rs | 7 +++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/farming/logics/lib.rs b/farming/logics/lib.rs index ccb765d..8dadbc2 100644 --- a/farming/logics/lib.rs +++ b/farming/logics/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] #![feature(min_specialization)] +#![feature(mixed_integer_ops)] pub mod helpers; pub mod traits; diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs index 6571988..f542b3b 100644 --- a/farming/logics/traits/master_chef/errors.rs +++ b/farming/logics/traits/master_chef/errors.rs @@ -56,6 +56,8 @@ pub enum FarmingError { AddOverflow10, AddOverflow11, AddOverflow12, + AddOverflow13, + AddOverflow14, MulOverflow1, MulOverflow2, MulOverflow3, diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index e71b3fe..a7dacdd 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -151,7 +151,8 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .checked_mul(acc_arsw_per_share) .ok_or(FarmingError::MulOverflow9)? / ACC_ARSW_PRECISION) - .wrapping_add(user_info.reward_debt as u128); + .checked_add_signed(-user_info.reward_debt) + .ok_or(FarmingError::AddOverflow14)?; Ok(pending) } @@ -278,7 +279,9 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::MulOverflow12)? / ACC_ARSW_PRECISION; - let pending_arsw = accumulated_arsw.wrapping_add(user.reward_debt as u128); + let pending_arsw = accumulated_arsw + .checked_add_signed(-user.reward_debt) + .ok_or(FarmingError::AddOverflow13)?; self.data::().user_info.insert( &(pool_id, to), From 3785d6620137a3ab1765ffc320feffcced312663 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 28 Oct 2022 15:20:08 +0200 Subject: [PATCH 31/36] Added deposit_arsw + emergency_withdraw + withdraw_and_harvest --- farming/logics/helpers/helper.rs | 8 ++ farming/logics/helpers/mod.rs | 1 + farming/logics/traits/master_chef/errors.rs | 16 ++- farming/logics/traits/master_chef/farming.rs | 140 +++++++++++++++++-- 4 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 farming/logics/helpers/helper.rs diff --git a/farming/logics/helpers/helper.rs b/farming/logics/helpers/helper.rs new file mode 100644 index 0000000..f42bcef --- /dev/null +++ b/farming/logics/helpers/helper.rs @@ -0,0 +1,8 @@ +#[macro_export] +macro_rules! ensure { + ( $x:expr, $y:expr $(,)? ) => {{ + if !$x { + return Err($y.into()) + } + }}; +} diff --git a/farming/logics/helpers/mod.rs b/farming/logics/helpers/mod.rs index b8135c3..97d3d60 100644 --- a/farming/logics/helpers/mod.rs +++ b/farming/logics/helpers/mod.rs @@ -1 +1,2 @@ +pub mod helper; pub mod math; diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs index f542b3b..1bcff48 100644 --- a/farming/logics/traits/master_chef/errors.rs +++ b/farming/logics/traits/master_chef/errors.rs @@ -10,14 +10,9 @@ pub enum FarmingError { OwnableError(OwnableError), PSP22Error(PSP22Error), RewarderError(RewarderError), + AmountShouldBeGreaterThanZero, DuplicateLPToken, - PoolNotFound1, - PoolNotFound2, - PoolNotFound3, - PoolNotFound4, - PoolNotFound5, - PoolNotFound6, - PoolNotFound7, + PoolNotFound, UserNotFound, ZeroWithdrawal, LpTokenNotFound, @@ -29,11 +24,14 @@ pub enum FarmingError { CastTou128Error4, CastTou128Error5, CastTou128Error6, + CastTou128Error7, CastToi128Error, CastToi128Error2, CastToi128Error3, CastToi128Error4, CastToi128Error5, + CastToi128Error6, + CastToi128Error7, RewarderNotFound, SubUnderflow1, SubUnderflow2, @@ -44,6 +42,7 @@ pub enum FarmingError { SubUnderflow7, SubUnderflow8, SubUnderflow9, + SubUnderflow10, AddOverflow1, AddOverflow2, AddOverflow3, @@ -58,6 +57,8 @@ pub enum FarmingError { AddOverflow12, AddOverflow13, AddOverflow14, + AddOverflow15, + AddOverflow16, MulOverflow1, MulOverflow2, MulOverflow3, @@ -70,6 +71,7 @@ pub enum FarmingError { MulOverflow10, MulOverflow11, MulOverflow12, + MulOverflow13, PowOverflow1, PowOverflow2, DivByZero1, diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index a7dacdd..cb93fa8 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -10,12 +10,14 @@ pub use crate::traits::{ rewarder::rewarder::RewarderRef, }; use crate::{ + ensure, helpers::math::casted_mul, traits::master_chef::{ data::UserInfo, errors::FarmingError, }, }; +use ink_env::CallFlags; use ink_prelude::vec::Vec; use openbrush::{ contracts::{ @@ -91,7 +93,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far ) -> Result<(), FarmingError> { let pool_info = self .get_pool_infos(pool_id) - .ok_or(FarmingError::PoolNotFound5)?; + .ok_or(FarmingError::PoolNotFound)?; self._update_all_pools()?; self.data::().total_alloc_point = self .data::() @@ -129,7 +131,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far fn pending_arsw(&self, pool_id: u32, user: AccountId) -> Result { let pool = self .get_pool_infos(pool_id) - .ok_or(FarmingError::PoolNotFound4)?; + .ok_or(FarmingError::PoolNotFound)?; let user_info = self .get_user_info(pool_id, user) .ok_or(FarmingError::UserNotFound)?; @@ -166,7 +168,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far ) -> Result<(), FarmingError> { let pool = self .get_pool_infos(pool_id) - .ok_or(FarmingError::PoolNotFound4)?; + .ok_or(FarmingError::PoolNotFound)?; self._update_pool(pool_id)?; let user = self.get_user_info(pool_id, to).unwrap_or_default(); let user_amount = user @@ -197,7 +199,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let lp_token = self .get_lp_token(pool_id) - .ok_or(FarmingError::PoolNotFound2)?; + .ok_or(FarmingError::PoolNotFound)?; PSP22Ref::transfer_from( &lp_token, Self::env().caller(), @@ -221,7 +223,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } let pool = self .get_pool_infos(pool_id) - .ok_or(FarmingError::PoolNotFound6)?; + .ok_or(FarmingError::PoolNotFound)?; self._update_pool(pool_id)?; let caller = Self::env().caller(); let user = self @@ -256,7 +258,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let lp_token = self .get_lp_token(pool_id) - .ok_or(FarmingError::PoolNotFound3)?; + .ok_or(FarmingError::LpTokenNotFound)?; PSP22Ref::transfer(&lp_token, to, amount, Vec::new())?; self._emit_withdraw_event(caller, pool_id, amount, to); Ok(()) @@ -266,7 +268,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far fn harvest(&mut self, pool_id: u32, to: AccountId) -> Result<(), FarmingError> { let pool = self .get_pool_infos(pool_id) - .ok_or(FarmingError::PoolNotFound7)?; + .ok_or(FarmingError::PoolNotFound)?; self._update_pool(pool_id)?; let caller = Self::env().caller(); let user = self @@ -317,6 +319,128 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far Ok(()) } + #[ink(message)] + fn withdraw_and_harvest( + &mut self, + pool_id: u32, + amount: Balance, + to: AccountId, + ) -> Result<(), FarmingError> { + let pool = self + .get_pool_infos(pool_id) + .ok_or(FarmingError::PoolNotFound)?; + self._update_pool(pool_id)?; + let caller = Self::env().caller(); + let user = self + .get_user_info(pool_id, caller) + .ok_or(FarmingError::UserNotFound)?; + + let accumulated_arsw = user + .amount + .checked_mul(pool.acc_arsw_per_share) + .ok_or(FarmingError::MulOverflow13)? + / ACC_ARSW_PRECISION; + + let pending_arsw = accumulated_arsw + .checked_add_signed(-user.reward_debt) + .ok_or(FarmingError::AddOverflow15)?; + + let user_reward_debt = accumulated_arsw + .checked_sub( + (casted_mul(amount, pool.acc_arsw_per_share) / ACC_ARSW_PRECISION) + .try_into() + .map_err(|_| FarmingError::CastTou128Error7)?, + ) + .ok_or(FarmingError::SubUnderflow10)?; + + let user_amount = user + .amount + .checked_sub(amount) + .ok_or(FarmingError::AddOverflow16)?; + + self.data::().user_info.insert( + &(pool_id, to), + &UserInfo { + reward_debt: user_reward_debt + .try_into() + .map_err(|_| FarmingError::CastToi128Error7)?, + amount: user_amount, + }, + ); + + PSP22Ref::transfer( + &mut self.data::().arsw_token, + to, + pending_arsw, + Vec::new(), + )?; + if let Some(rewarder_address) = self.get_rewarder(pool_id) { + RewarderRef::on_arsw_reward( + &rewarder_address, + pool_id, + caller, + to, + pending_arsw, + user.amount, + )?; + } + let lp_token = self + .get_lp_token(pool_id) + .ok_or(FarmingError::LpTokenNotFound)?; + PSP22Ref::transfer(&lp_token, to, amount, Vec::new())?; + + self._emit_harvest_event(caller, pool_id, pending_arsw); + self._emit_withdraw_event(caller, pool_id, amount, to); + Ok(()) + } + + #[ink(message)] + fn emergency_withdraw(&mut self, pool_id: u32, to: AccountId) -> Result<(), FarmingError> { + let caller = Self::env().caller(); + let user = self + .get_user_info(pool_id, caller) + .ok_or(FarmingError::UserNotFound)?; + let amount = user.amount; + self.data::().user_info.insert( + &(pool_id, to), + &UserInfo { + reward_debt: 0, + amount: 0, + }, + ); + + if let Some(rewarder_address) = self.get_rewarder(pool_id) { + RewarderRef::on_arsw_reward(&rewarder_address, pool_id, caller, to, 0, 0)?; + } + + let lp_token = self + .get_lp_token(pool_id) + .ok_or(FarmingError::LpTokenNotFound)?; + PSP22Ref::transfer(&lp_token, to, amount, Vec::new())?; + + self._emit_emergency_withdraw_event(caller, pool_id, amount, to); + Ok(()) + } + + #[ink(message)] + #[modifiers(only_owner)] + fn deposit_arsw(&mut self, amount: Balance) -> Result<(), FarmingError> { + ensure!(amount > 0, FarmingError::AmountShouldBeGreaterThanZero); + let caller = Self::env().caller(); + PSP22Ref::transfer_from_builder( + &mut self.data::().arsw_token, + caller, + Self::env().account_id(), + amount, + Vec::new(), + ) + .call_flags(CallFlags::default().set_allow_reentry(true)) + .fire() + .unwrap()?; + self._emit_deposit_arsw_event(Self::env().block_number(), amount); + Ok(()) + } + fn _check_pool_duplicate(&self, lp_token: AccountId) -> Result<(), FarmingError> { let lp_tokens = &self.data::().lp_tokens; if lp_tokens.iter().any(|lp| *lp == lp_token) { @@ -336,7 +460,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far fn _update_pool(&mut self, pool_id: u32) -> Result<(), FarmingError> { let mut pool = self .get_pool_infos(pool_id) - .ok_or(FarmingError::PoolNotFound1)?; + .ok_or(FarmingError::PoolNotFound)?; let current_block = Self::env().block_number(); if current_block > pool.last_reward_block { let lp_supply = self._get_lp_supply(pool_id)?; From dd34a0bd38dcd066495a5517dbab80af790812ba Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 28 Oct 2022 15:25:25 +0200 Subject: [PATCH 32/36] refactor guards --- farming/logics/traits/master_chef/errors.rs | 1 - farming/logics/traits/master_chef/farming.rs | 24 +++++++++----------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs index 1bcff48..10172d3 100644 --- a/farming/logics/traits/master_chef/errors.rs +++ b/farming/logics/traits/master_chef/errors.rs @@ -10,7 +10,6 @@ pub enum FarmingError { OwnableError(OwnableError), PSP22Error(PSP22Error), RewarderError(RewarderError), - AmountShouldBeGreaterThanZero, DuplicateLPToken, PoolNotFound, UserNotFound, diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index cb93fa8..53adb22 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -218,9 +218,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far amount: Balance, to: AccountId, ) -> Result<(), FarmingError> { - if amount == 0 { - return Err(FarmingError::ZeroWithdrawal) - } + ensure!(amount > 0, FarmingError::ZeroWithdrawal); let pool = self .get_pool_infos(pool_id) .ok_or(FarmingError::PoolNotFound)?; @@ -425,7 +423,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far #[ink(message)] #[modifiers(only_owner)] fn deposit_arsw(&mut self, amount: Balance) -> Result<(), FarmingError> { - ensure!(amount > 0, FarmingError::AmountShouldBeGreaterThanZero); + ensure!(amount > 0, FarmingError::ZeroWithdrawal); let caller = Self::env().caller(); PSP22Ref::transfer_from_builder( &mut self.data::().arsw_token, @@ -443,9 +441,10 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far fn _check_pool_duplicate(&self, lp_token: AccountId) -> Result<(), FarmingError> { let lp_tokens = &self.data::().lp_tokens; - if lp_tokens.iter().any(|lp| *lp == lp_token) { - return Err(FarmingError::DuplicateLPToken) - } + ensure!( + !lp_tokens.iter().any(|lp| *lp == lp_token), + FarmingError::DuplicateLPToken + ); Ok(()) } @@ -491,9 +490,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far current_block: u32, lp_supply: Balance, ) -> Result { - if lp_supply == 0 { - return Err(FarmingError::LpSupplyIsZero) - } + ensure!(lp_supply > 0, FarmingError::LpSupplyIsZero); let last_reward_block_period = self._get_period(pool_info.last_reward_block)?; let current_period = self._get_period(Self::env().block_number())?; @@ -554,9 +551,10 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far } fn _get_period(&self, block_number: u32) -> Result { - if block_number < ARTHSWAP_ORIGIN_BLOCK { - return Err(FarmingError::BlockNumberLowerThanOriginBlock) - } + ensure!( + block_number >= ARTHSWAP_ORIGIN_BLOCK, + FarmingError::BlockNumberLowerThanOriginBlock + ); // BLOCK_PER_PERIOD is never 0 return Ok(block_number From 995eb296896b523256b813e84b2895f5c06cc997 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Mon, 31 Oct 2022 09:27:24 +0100 Subject: [PATCH 33/36] PR comments - clean code --- farming/logics/traits/master_chef/farming.rs | 14 +++++++------- farming/logics/traits/master_chef/getters.rs | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index 53adb22..ecb2313 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -92,7 +92,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far overwrite: bool, ) -> Result<(), FarmingError> { let pool_info = self - .get_pool_infos(pool_id) + .get_pool_info(pool_id) .ok_or(FarmingError::PoolNotFound)?; self._update_all_pools()?; self.data::().total_alloc_point = self @@ -130,7 +130,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far #[ink(message)] fn pending_arsw(&self, pool_id: u32, user: AccountId) -> Result { let pool = self - .get_pool_infos(pool_id) + .get_pool_info(pool_id) .ok_or(FarmingError::PoolNotFound)?; let user_info = self .get_user_info(pool_id, user) @@ -167,7 +167,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far to: AccountId, ) -> Result<(), FarmingError> { let pool = self - .get_pool_infos(pool_id) + .get_pool_info(pool_id) .ok_or(FarmingError::PoolNotFound)?; self._update_pool(pool_id)?; let user = self.get_user_info(pool_id, to).unwrap_or_default(); @@ -220,7 +220,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far ) -> Result<(), FarmingError> { ensure!(amount > 0, FarmingError::ZeroWithdrawal); let pool = self - .get_pool_infos(pool_id) + .get_pool_info(pool_id) .ok_or(FarmingError::PoolNotFound)?; self._update_pool(pool_id)?; let caller = Self::env().caller(); @@ -265,7 +265,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far #[ink(message)] fn harvest(&mut self, pool_id: u32, to: AccountId) -> Result<(), FarmingError> { let pool = self - .get_pool_infos(pool_id) + .get_pool_info(pool_id) .ok_or(FarmingError::PoolNotFound)?; self._update_pool(pool_id)?; let caller = Self::env().caller(); @@ -325,7 +325,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far to: AccountId, ) -> Result<(), FarmingError> { let pool = self - .get_pool_infos(pool_id) + .get_pool_info(pool_id) .ok_or(FarmingError::PoolNotFound)?; self._update_pool(pool_id)?; let caller = Self::env().caller(); @@ -458,7 +458,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far fn _update_pool(&mut self, pool_id: u32) -> Result<(), FarmingError> { let mut pool = self - .get_pool_infos(pool_id) + .get_pool_info(pool_id) .ok_or(FarmingError::PoolNotFound)?; let current_block = Self::env().block_number(); if current_block > pool.last_reward_block { diff --git a/farming/logics/traits/master_chef/getters.rs b/farming/logics/traits/master_chef/getters.rs index 59bafa3..6bc7da4 100644 --- a/farming/logics/traits/master_chef/getters.rs +++ b/farming/logics/traits/master_chef/getters.rs @@ -16,7 +16,7 @@ pub trait FarmingGetters: Storage { } #[ink(message)] - fn get_pool_infos(&self, pool_id: u32) -> Option { + fn get_pool_info(&self, pool_id: u32) -> Option { self.data::().pool_info.get(&pool_id) } From 115d004d9237e7701e856bcabaefb0a3f8bade32 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Mon, 31 Oct 2022 15:58:02 +0100 Subject: [PATCH 34/36] PR comments --- farming/logics/traits/master_chef/errors.rs | 4 + farming/logics/traits/master_chef/farming.rs | 110 ++++++++----------- 2 files changed, 52 insertions(+), 62 deletions(-) diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs index 10172d3..3ea2f7a 100644 --- a/farming/logics/traits/master_chef/errors.rs +++ b/farming/logics/traits/master_chef/errors.rs @@ -24,6 +24,7 @@ pub enum FarmingError { CastTou128Error5, CastTou128Error6, CastTou128Error7, + CastTou128Error8, CastToi128Error, CastToi128Error2, CastToi128Error3, @@ -31,6 +32,7 @@ pub enum FarmingError { CastToi128Error5, CastToi128Error6, CastToi128Error7, + CastToi128Error8, RewarderNotFound, SubUnderflow1, SubUnderflow2, @@ -42,6 +44,8 @@ pub enum FarmingError { SubUnderflow8, SubUnderflow9, SubUnderflow10, + SubUnderflow11, + SubUnderflow12, AddOverflow1, AddOverflow2, AddOverflow3, diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index ecb2313..894512d 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -54,8 +54,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far self._update_all_pools()?; self.data::().total_alloc_point = self - .data::() - .total_alloc_point + .get_total_alloc_point() .checked_add(alloc_point) .ok_or(FarmingError::AddOverflow2)?; self.data::().lp_tokens.push(lp_token); @@ -96,8 +95,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::PoolNotFound)?; self._update_all_pools()?; self.data::().total_alloc_point = self - .data::() - .total_alloc_point + .get_total_alloc_point() .checked_sub(pool_info.alloc_point) .ok_or(FarmingError::SubUnderflow7)? .checked_add(alloc_point) @@ -148,13 +146,12 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::AddOverflow8)?; } - let pending = (user_info - .amount - .checked_mul(acc_arsw_per_share) - .ok_or(FarmingError::MulOverflow9)? - / ACC_ARSW_PRECISION) - .checked_add_signed(-user_info.reward_debt) - .ok_or(FarmingError::AddOverflow14)?; + let pending = >::try_into( + casted_mul(user_info.amount, acc_arsw_per_share) / ACC_ARSW_PRECISION, + ) + .map_err(|_| FarmingError::CastTou128Error8)? + .checked_add_signed(-user_info.reward_debt) + .ok_or(FarmingError::AddOverflow14)?; Ok(pending) } @@ -240,7 +237,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let user_amount = user .amount .checked_sub(amount) - .ok_or(FarmingError::AddOverflow12)?; + .ok_or(FarmingError::SubUnderflow12)?; self.data::().user_info.insert( &(pool_id, to), @@ -273,22 +270,19 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .get_user_info(pool_id, caller) .ok_or(FarmingError::UserNotFound)?; - let accumulated_arsw = user - .amount - .checked_mul(pool.acc_arsw_per_share) - .ok_or(FarmingError::MulOverflow12)? - / ACC_ARSW_PRECISION; + let accumulated_arsw = >::try_into( + casted_mul(user.amount, pool.acc_arsw_per_share) / ACC_ARSW_PRECISION, + ) + .map_err(|_| FarmingError::CastToi128Error8)?; let pending_arsw = accumulated_arsw - .checked_add_signed(-user.reward_debt) - .ok_or(FarmingError::AddOverflow13)?; + .checked_sub(user.reward_debt) + .ok_or(FarmingError::SubUnderflow11)? as u128; self.data::().user_info.insert( &(pool_id, to), &UserInfo { - reward_debt: accumulated_arsw - .try_into() - .map_err(|_| FarmingError::CastToi128Error5)?, + reward_debt: accumulated_arsw, ..user }, ); @@ -333,23 +327,19 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .get_user_info(pool_id, caller) .ok_or(FarmingError::UserNotFound)?; - let accumulated_arsw = user - .amount - .checked_mul(pool.acc_arsw_per_share) - .ok_or(FarmingError::MulOverflow13)? - / ACC_ARSW_PRECISION; + let accumulated_arsw = + casted_mul(user.amount, pool.acc_arsw_per_share) / ACC_ARSW_PRECISION; - let pending_arsw = accumulated_arsw + let pending_arsw = >::try_into(accumulated_arsw) + .map_err(|_| FarmingError::CastTou128Error8)? .checked_add_signed(-user.reward_debt) .ok_or(FarmingError::AddOverflow15)?; - let user_reward_debt = accumulated_arsw - .checked_sub( - (casted_mul(amount, pool.acc_arsw_per_share) / ACC_ARSW_PRECISION) - .try_into() - .map_err(|_| FarmingError::CastTou128Error7)?, - ) - .ok_or(FarmingError::SubUnderflow10)?; + let user_reward_debt: i128 = accumulated_arsw + .checked_sub(casted_mul(amount, pool.acc_arsw_per_share) / ACC_ARSW_PRECISION) + .ok_or(FarmingError::SubUnderflow10)? + .try_into() + .map_err(|_| FarmingError::CastTou128Error7)?; let user_amount = user .amount @@ -359,15 +349,13 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far self.data::().user_info.insert( &(pool_id, to), &UserInfo { - reward_debt: user_reward_debt - .try_into() - .map_err(|_| FarmingError::CastToi128Error7)?, + reward_debt: user_reward_debt, amount: user_amount, }, ); PSP22Ref::transfer( - &mut self.data::().arsw_token, + &self.data::().arsw_token, to, pending_arsw, Vec::new(), @@ -387,8 +375,8 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::LpTokenNotFound)?; PSP22Ref::transfer(&lp_token, to, amount, Vec::new())?; - self._emit_harvest_event(caller, pool_id, pending_arsw); self._emit_withdraw_event(caller, pool_id, amount, to); + self._emit_harvest_event(caller, pool_id, pending_arsw); Ok(()) } @@ -472,7 +460,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .ok_or(FarmingError::AddOverflow8)?; } pool.last_reward_block = current_block; - self.data::().pool_info.insert(pool_id, &pool); + self.data::().pool_info.insert(&pool_id, &pool); self._emit_log_update_pool_event( pool_id, @@ -491,17 +479,16 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far lp_supply: Balance, ) -> Result { ensure!(lp_supply > 0, FarmingError::LpSupplyIsZero); - let last_reward_block_period = self._get_period(pool_info.last_reward_block)?; - let current_period = self._get_period(Self::env().block_number())?; - + let current_period = self._get_period(current_block)?; let mut arsw_reward: Balance = 0; let mut last_block = pool_info.last_reward_block; + let last_reward_block_period = self._get_period(last_block)?; let mut period = last_reward_block_period; + let total_alloc_point = self.get_total_alloc_point(); while period <= current_period { if period > MAX_PERIOD { break } - let total_alloc_point: u32 = self.data::().total_alloc_point; if current_block <= self._period_max(period)? { arsw_reward = arsw_reward .checked_add( @@ -509,9 +496,8 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far (current_block .checked_sub(last_block) .ok_or(FarmingError::SubUnderflow4)? - as u128) - .checked_add(pool_info.alloc_point as u128) - .ok_or(FarmingError::MulOverflow4)?, + * pool_info.alloc_point) + .into(), self._arsw_per_block(period)?, ) .checked_div(total_alloc_point.into()) @@ -524,11 +510,12 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far arsw_reward = arsw_reward .checked_add( casted_mul( - (self._period_max(period)? as u128) + (self + ._period_max(period)? .checked_sub(last_block.into()) .ok_or(FarmingError::SubUnderflow5)? - .checked_mul(pool_info.alloc_point.into()) - .ok_or(FarmingError::MulOverflow6)?, + * pool_info.alloc_point) + .into(), self._arsw_per_block(period)? as u128, ) .checked_div(total_alloc_point.into()) @@ -543,11 +530,11 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far period += 1; } - Ok(casted_mul(arsw_reward, ACC_ARSW_PRECISION) - .checked_div(lp_supply.into()) - .ok_or(FarmingError::DivByZero3)? - .try_into() - .map_err(|_| FarmingError::CastTou128Error6)?) + Ok( + (casted_mul(arsw_reward, ACC_ARSW_PRECISION) / U256::from(lp_supply)) + .try_into() + .map_err(|_| FarmingError::CastTou128Error6)?, + ) } fn _get_period(&self, block_number: u32) -> Result { @@ -578,15 +565,14 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far if period > MAX_PERIOD { return Ok(0) } - Ok(casted_mul( + Ok((casted_mul( FIRST_PERIOD_REWERD_SUPPLY, 9u128 .checked_pow(period) - .ok_or(FarmingError::PowOverflow1)? - / 10u128 - .checked_pow(period) - .ok_or(FarmingError::PowOverflow2)?, - ) + .ok_or(FarmingError::PowOverflow1)?, + ) / 10u128 + .checked_pow(period) + .ok_or(FarmingError::PowOverflow2)?) .try_into() .map_err(|_| FarmingError::CastTou128Error5)?) } From ce7eab0f6b80590fd32afd2ea9ef6a4704f58670 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 4 Nov 2022 10:18:38 +0100 Subject: [PATCH 35/36] cast as u128 --- farming/logics/traits/master_chef/farming.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index 894512d..629b3b2 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -493,11 +493,11 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far arsw_reward = arsw_reward .checked_add( casted_mul( - (current_block + current_block .checked_sub(last_block) .ok_or(FarmingError::SubUnderflow4)? - * pool_info.alloc_point) - .into(), + as u128 + * pool_info.alloc_point as u128, self._arsw_per_block(period)?, ) .checked_div(total_alloc_point.into()) @@ -510,12 +510,11 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far arsw_reward = arsw_reward .checked_add( casted_mul( - (self - ._period_max(period)? + self._period_max(period)? .checked_sub(last_block.into()) .ok_or(FarmingError::SubUnderflow5)? - * pool_info.alloc_point) - .into(), + as u128 + * pool_info.alloc_point as u128, self._arsw_per_block(period)? as u128, ) .checked_div(total_alloc_point.into()) From cd310b98728881f40ddc06402b03b01bb321f1e6 Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Fri, 4 Nov 2022 10:54:07 +0100 Subject: [PATCH 36/36] Fixed error enum --- farming/logics/traits/master_chef/errors.rs | 29 +--------- farming/logics/traits/master_chef/farming.rs | 60 ++++++++++---------- 2 files changed, 31 insertions(+), 58 deletions(-) diff --git a/farming/logics/traits/master_chef/errors.rs b/farming/logics/traits/master_chef/errors.rs index 3ea2f7a..ec3ad5b 100644 --- a/farming/logics/traits/master_chef/errors.rs +++ b/farming/logics/traits/master_chef/errors.rs @@ -24,15 +24,9 @@ pub enum FarmingError { CastTou128Error5, CastTou128Error6, CastTou128Error7, - CastTou128Error8, - CastToi128Error, + CastToi128Error1, CastToi128Error2, CastToi128Error3, - CastToi128Error4, - CastToi128Error5, - CastToi128Error6, - CastToi128Error7, - CastToi128Error8, RewarderNotFound, SubUnderflow1, SubUnderflow2, @@ -42,10 +36,6 @@ pub enum FarmingError { SubUnderflow6, SubUnderflow7, SubUnderflow8, - SubUnderflow9, - SubUnderflow10, - SubUnderflow11, - SubUnderflow12, AddOverflow1, AddOverflow2, AddOverflow3, @@ -58,28 +48,11 @@ pub enum FarmingError { AddOverflow10, AddOverflow11, AddOverflow12, - AddOverflow13, - AddOverflow14, - AddOverflow15, - AddOverflow16, MulOverflow1, - MulOverflow2, - MulOverflow3, - MulOverflow4, - MulOverflow5, - MulOverflow6, - MulOverflow7, - MulOverflow8, - MulOverflow9, - MulOverflow10, - MulOverflow11, - MulOverflow12, - MulOverflow13, PowOverflow1, PowOverflow2, DivByZero1, DivByZero2, - DivByZero3, } impl From for FarmingError { diff --git a/farming/logics/traits/master_chef/farming.rs b/farming/logics/traits/master_chef/farming.rs index 629b3b2..afc580d 100644 --- a/farming/logics/traits/master_chef/farming.rs +++ b/farming/logics/traits/master_chef/farming.rs @@ -56,7 +56,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far self.data::().total_alloc_point = self .get_total_alloc_point() .checked_add(alloc_point) - .ok_or(FarmingError::AddOverflow2)?; + .ok_or(FarmingError::AddOverflow1)?; self.data::().lp_tokens.push(lp_token); let pool_length = self.pool_length(); @@ -75,7 +75,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far ); self.data::().pool_info_length = pool_length .checked_add(1) - .ok_or(FarmingError::AddOverflow2)?; + .ok_or(FarmingError::AddOverflow1)?; self._emit_log_pool_addition_event(pool_length, alloc_point, lp_token, rewarder); Ok(()) @@ -97,9 +97,9 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far self.data::().total_alloc_point = self .get_total_alloc_point() .checked_sub(pool_info.alloc_point) - .ok_or(FarmingError::SubUnderflow7)? + .ok_or(FarmingError::SubUnderflow4)? .checked_add(alloc_point) - .ok_or(FarmingError::AddOverflow9)?; + .ok_or(FarmingError::AddOverflow7)?; self.data::().pool_info.insert( &pool_id, @@ -143,15 +143,15 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far self._calculate_additional_acc_arsw_per_share(&pool, current_block, lp_supply)?; acc_arsw_per_share = acc_arsw_per_share .checked_add(additional_acc_arsw_per_share) - .ok_or(FarmingError::AddOverflow8)?; + .ok_or(FarmingError::AddOverflow6)?; } let pending = >::try_into( casted_mul(user_info.amount, acc_arsw_per_share) / ACC_ARSW_PRECISION, ) - .map_err(|_| FarmingError::CastTou128Error8)? + .map_err(|_| FarmingError::CastTou128Error7)? .checked_add_signed(-user_info.reward_debt) - .ok_or(FarmingError::AddOverflow14)?; + .ok_or(FarmingError::AddOverflow10)?; Ok(pending) } @@ -171,16 +171,16 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let user_amount = user .amount .checked_add(amount) - .ok_or(FarmingError::AddOverflow10)?; + .ok_or(FarmingError::AddOverflow8)?; let user_reward_debt = user .reward_debt .checked_add( >::try_into( casted_mul(amount, pool.acc_arsw_per_share) / ACC_ARSW_PRECISION, ) - .map_err(|_| FarmingError::CastToi128Error2)?, + .map_err(|_| FarmingError::CastTou128Error1)?, ) - .ok_or(FarmingError::AddOverflow11)?; + .ok_or(FarmingError::AddOverflow9)?; self.data::().user_info.insert( &(pool_id, to), @@ -230,14 +230,14 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far >::try_into( casted_mul(amount, pool.acc_arsw_per_share) / ACC_ARSW_PRECISION, ) - .map_err(|_| FarmingError::CastToi128Error4)?, + .map_err(|_| FarmingError::CastTou128Error2)?, ) - .ok_or(FarmingError::SubUnderflow8)?; + .ok_or(FarmingError::SubUnderflow5)?; let user_amount = user .amount .checked_sub(amount) - .ok_or(FarmingError::SubUnderflow12)?; + .ok_or(FarmingError::SubUnderflow8)?; self.data::().user_info.insert( &(pool_id, to), @@ -273,11 +273,11 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far let accumulated_arsw = >::try_into( casted_mul(user.amount, pool.acc_arsw_per_share) / ACC_ARSW_PRECISION, ) - .map_err(|_| FarmingError::CastToi128Error8)?; + .map_err(|_| FarmingError::CastTou128Error3)?; let pending_arsw = accumulated_arsw .checked_sub(user.reward_debt) - .ok_or(FarmingError::SubUnderflow11)? as u128; + .ok_or(FarmingError::SubUnderflow7)? as u128; self.data::().user_info.insert( &(pool_id, to), @@ -331,20 +331,20 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far casted_mul(user.amount, pool.acc_arsw_per_share) / ACC_ARSW_PRECISION; let pending_arsw = >::try_into(accumulated_arsw) - .map_err(|_| FarmingError::CastTou128Error8)? + .map_err(|_| FarmingError::CastTou128Error6)? .checked_add_signed(-user.reward_debt) - .ok_or(FarmingError::AddOverflow15)?; + .ok_or(FarmingError::AddOverflow11)?; let user_reward_debt: i128 = accumulated_arsw .checked_sub(casted_mul(amount, pool.acc_arsw_per_share) / ACC_ARSW_PRECISION) - .ok_or(FarmingError::SubUnderflow10)? + .ok_or(FarmingError::SubUnderflow6)? .try_into() - .map_err(|_| FarmingError::CastTou128Error7)?; + .map_err(|_| FarmingError::CastTou128Error5)?; let user_amount = user .amount .checked_sub(amount) - .ok_or(FarmingError::AddOverflow16)?; + .ok_or(FarmingError::AddOverflow12)?; self.data::().user_info.insert( &(pool_id, to), @@ -457,7 +457,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far pool.acc_arsw_per_share = pool .acc_arsw_per_share .checked_add(additional_acc_arsw_per_share) - .ok_or(FarmingError::AddOverflow8)?; + .ok_or(FarmingError::AddOverflow6)?; } pool.last_reward_block = current_block; self.data::().pool_info.insert(&pool_id, &pool); @@ -495,7 +495,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far casted_mul( current_block .checked_sub(last_block) - .ok_or(FarmingError::SubUnderflow4)? + .ok_or(FarmingError::SubUnderflow2)? as u128 * pool_info.alloc_point as u128, self._arsw_per_block(period)?, @@ -505,14 +505,14 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .try_into() .map_err(|_| FarmingError::CastTou128Error1)?, ) - .ok_or(FarmingError::AddOverflow6)?; + .ok_or(FarmingError::AddOverflow4)?; } else { arsw_reward = arsw_reward .checked_add( casted_mul( self._period_max(period)? .checked_sub(last_block.into()) - .ok_or(FarmingError::SubUnderflow5)? + .ok_or(FarmingError::SubUnderflow3)? as u128 * pool_info.alloc_point as u128, self._arsw_per_block(period)? as u128, @@ -520,9 +520,9 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .checked_div(total_alloc_point.into()) .ok_or(FarmingError::DivByZero2)? .try_into() - .map_err(|_| FarmingError::CastTou128Error3)?, + .map_err(|_| FarmingError::CastTou128Error2)?, ) - .ok_or(FarmingError::AddOverflow7)?; + .ok_or(FarmingError::AddOverflow5)?; last_block = self._period_max(period)?; } @@ -532,7 +532,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far Ok( (casted_mul(arsw_reward, ACC_ARSW_PRECISION) / U256::from(lp_supply)) .try_into() - .map_err(|_| FarmingError::CastTou128Error6)?, + .map_err(|_| FarmingError::CastTou128Error4)?, ) } @@ -553,10 +553,10 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far Ok(ARTHSWAP_ORIGIN_BLOCK .checked_add( BLOCK_PER_PERIOD - .checked_mul(period.checked_add(1).ok_or(FarmingError::AddOverflow4)?) + .checked_mul(period.checked_add(1).ok_or(FarmingError::AddOverflow2)?) .ok_or(FarmingError::MulOverflow1)?, ) - .ok_or(FarmingError::AddOverflow5)? + .ok_or(FarmingError::AddOverflow3)? - 1) } @@ -573,7 +573,7 @@ pub trait Farming: Storage + Storage + FarmingGetters + Far .checked_pow(period) .ok_or(FarmingError::PowOverflow2)?) .try_into() - .map_err(|_| FarmingError::CastTou128Error5)?) + .map_err(|_| FarmingError::CastTou128Error3)?) } fn _get_lp_supply(&self, pool_id: u32) -> Result {