Skip to content

Commit

Permalink
fix: add extrinsics to set Apy and genesis configs for rewards pallet (
Browse files Browse the repository at this point in the history
…#900)

* add extrinsic

* add genesis config

* clippy
  • Loading branch information
1xstj authored Jan 29, 2025
1 parent 3d82ceb commit 7ecc5cb
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 36 deletions.
13 changes: 6 additions & 7 deletions pallets/rewards/src/functions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@
//
// You should have received a copy of the GNU General Public License
// along with Tangle. If not, see <http://www.gnu.org/licenses/>.
use crate::RewardVaultsPotAccount;
use crate::SubaccountType;
use crate::{AssetLookupRewardVaults, Config, Error, Pallet, RewardVaults};
use frame_support::ensure;
use frame_support::traits::Get;
use sp_runtime::traits::AccountIdConversion;
use sp_runtime::{DispatchError, DispatchResult};
use crate::{
AssetLookupRewardVaults, Config, Error, Pallet, RewardVaults, RewardVaultsPotAccount,
SubaccountType,
};
use frame_support::{ensure, traits::Get};
use sp_runtime::{traits::AccountIdConversion, DispatchError, DispatchResult};
use sp_std::vec::Vec;
use tangle_primitives::services::Asset;

Expand Down
9 changes: 3 additions & 6 deletions pallets/rewards/src/functions/rewards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,10 @@
//
// You should have received a copy of the GNU General Public License
// along with Tangle. If not, see <http://www.gnu.org/licenses/>.
use crate::DecayRate;
use crate::DecayStartPeriod;
use crate::RewardVaultsPotAccount;
use crate::{
ApyBlocks, AssetLookupRewardVaults, BalanceOf, Config, Error, Event, Pallet,
RewardConfigForAssetVault, RewardConfigStorage, TotalRewardVaultDeposit, TotalRewardVaultScore,
UserClaimedReward,
ApyBlocks, AssetLookupRewardVaults, BalanceOf, Config, DecayRate, DecayStartPeriod, Error,
Event, Pallet, RewardConfigForAssetVault, RewardConfigStorage, RewardVaultsPotAccount,
TotalRewardVaultDeposit, TotalRewardVaultScore, UserClaimedReward,
};
use frame_support::{ensure, traits::Currency};
use frame_system::pallet_prelude::BlockNumberFor;
Expand Down
54 changes: 52 additions & 2 deletions pallets/rewards/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub mod types;
pub use types::*;
pub mod functions;
pub mod impls;

use sp_std::vec::Vec;
use tangle_primitives::BlueprintId;

Expand All @@ -89,8 +90,7 @@ pub mod pallet {
PalletId,
};
use frame_system::pallet_prelude::*;
use sp_runtime::traits::AccountIdConversion;
use sp_runtime::Percent;
use sp_runtime::{traits::AccountIdConversion, Percent};
use tangle_primitives::rewards::LockMultiplier;

#[pallet::config]
Expand Down Expand Up @@ -259,6 +259,8 @@ pub mod pallet {
},
/// Decay configuration was updated
DecayConfigUpdated { start_period: BlockNumberFor<T>, rate: Percent },
/// The number of blocks for APY calculation has been updated
ApyBlocksUpdated { blocks: BlockNumberFor<T> },
}

#[pallet::error]
Expand Down Expand Up @@ -305,6 +307,38 @@ pub mod pallet {
InvalidDecayRate,
}

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
/// The number of blocks used for APY calculation
pub apy_blocks: BlockNumberFor<T>,
/// Number of blocks after which decay starts
pub decay_start_period: BlockNumberFor<T>,
/// Per-block decay rate in basis points
pub decay_rate: Percent,
}

impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
Self {
// Default to 1 year worth of blocks (assuming 6s block time)
apy_blocks: BlockNumberFor::<T>::from(5_256_000u32),
// Default to 30 days worth of blocks
decay_start_period: BlockNumberFor::<T>::from(432000u32),
// Default to 1% per block
decay_rate: Percent::from_percent(1),
}
}
}

#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
ApyBlocks::<T>::put(self.apy_blocks);
DecayStartPeriod::<T>::put(self.decay_start_period);
DecayRate::<T>::put(self.decay_rate);
}
}

#[pallet::call]
impl<T: Config> Pallet<T> {
/// Claim rewards for a specific asset and reward type
Expand Down Expand Up @@ -462,6 +496,22 @@ pub mod pallet {
Self::deposit_event(Event::DecayConfigUpdated { start_period, rate });
Ok(())
}

/// Update the number of blocks used for APY calculation
#[pallet::call_index(6)]
#[pallet::weight(T::DbWeight::get().writes(1))]
pub fn update_apy_blocks(
origin: OriginFor<T>,
blocks: BlockNumberFor<T>,
) -> DispatchResult {
T::ForceOrigin::ensure_origin(origin)?;

// Update the storage
ApyBlocks::<T>::put(blocks);

Self::deposit_event(Event::ApyBlocksUpdated { blocks });
Ok(())
}
}

impl<T: Config> Pallet<T> {
Expand Down
38 changes: 29 additions & 9 deletions pallets/rewards/src/tests/claim.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
use crate::AssetAction;
use crate::BalanceOf;
use crate::RewardConfigForAssetVault;
use crate::UserClaimedReward;
use crate::{
mock::*, tests::reward_calc::setup_test_env, DecayRate, DecayStartPeriod, Error,
Pallet as RewardsPallet, TotalRewardVaultDeposit, TotalRewardVaultScore,
mock::*, tests::reward_calc::setup_test_env, AssetAction, BalanceOf, DecayRate,
DecayStartPeriod, Error, Pallet as RewardsPallet, RewardConfigForAssetVault,
TotalRewardVaultDeposit, TotalRewardVaultScore, UserClaimedReward,
};
use frame_support::assert_noop;
use frame_support::{assert_ok, traits::Currency};
use frame_support::{assert_noop, assert_ok, traits::Currency};
use sp_runtime::Percent;
use tangle_primitives::rewards::UserDepositWithLocks;
use tangle_primitives::{
rewards::UserDepositWithLocks,
services::Asset,
types::rewards::{LockInfo, LockMultiplier},
};
Expand Down Expand Up @@ -506,3 +502,27 @@ fn test_claim_frequency_with_decay() {
assert!(difference_percent < 1);
});
}

#[test]
fn test_update_apy_blocks() {
new_test_ext_raw_authorities().execute_with(|| {
// Try updating APY blocks with non-root (should fail)
assert_noop!(
RewardsPallet::<Runtime>::update_apy_blocks(
RuntimeOrigin::signed(AccountId::new([1u8; 32])),
1000
),
sp_runtime::DispatchError::BadOrigin,
);

// Update APY blocks with root (should succeed)
assert_ok!(RewardsPallet::<Runtime>::update_apy_blocks(RuntimeOrigin::root(), 1000));

// Verify the storage was updated
assert_eq!(RewardsPallet::<Runtime>::blocks_for_apy(), 1000);

// Update to a different value
assert_ok!(RewardsPallet::<Runtime>::update_apy_blocks(RuntimeOrigin::root(), 2000));
assert_eq!(RewardsPallet::<Runtime>::blocks_for_apy(), 2000);
});
}
20 changes: 8 additions & 12 deletions pallets/rewards/src/tests/reward_calc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use sp_runtime::Percent;
use tangle_primitives::types::rewards::{LockInfo, LockMultiplier, UserDepositWithLocks};

// Mock values for consistent testing
use crate::DecayRate;
use crate::DecayStartPeriod;
use crate::{DecayRate, DecayStartPeriod};
const EIGHTEEN_DECIMALS: u128 = 1_000_000_000_000_000_000_000;
const MOCK_DEPOSIT_CAP: u128 = 1_000_000 * EIGHTEEN_DECIMALS; // 1M tokens with 18 decimals
const MOCK_TOTAL_ISSUANCE: u128 = 100_000_000 * EIGHTEEN_DECIMALS; // 100M tokens with 18 decimals
Expand Down Expand Up @@ -371,12 +370,11 @@ fn test_calculate_rewards_with_multiple_claims() {
// 1. User's total score = 10k (unlocked) + (10k * 2) (locked) = 30k
// 2. User's proportion = 30k / 200k = 15%
// 3. APY = 10% = 0.1 tokens per token per year
// 4. Rewards per block = (Total deposit * APY) / blocks_per_year
// = (100k * 0.1) / 3504 ≈ 2.85388127853881278 tokens/block
// 5. User reward per block = 2.85388127853881278 * 15%
// = 0.428538127853881278 tokens/block
// 6. Total reward for 1000 blocks = 0.428538127853881278 * 1000
// = 28.538812785388127853 tokens
// 4. Rewards per block = (Total deposit * APY) / blocks_per_year = (100k * 0.1) / 3504 ≈
// 2.85388127853881278 tokens/block
// 5. User reward per block = 2.85388127853881278 * 15% = 0.428538127853881278 tokens/block
// 6. Total reward for 1000 blocks = 0.428538127853881278 * 1000 = 28.538812785388127853
// tokens
System::set_block_number(1000);
let result1 = RewardsPallet::<Runtime>::calculate_deposit_rewards_with_lock_multiplier(
total_deposit,
Expand Down Expand Up @@ -428,10 +426,8 @@ fn test_calculate_rewards_with_multiple_claims() {
// 1. User's total score = 10k + 10k (unlocked + locked without multiplier)
// 2. User's proportion = 20k / 200k = 10%
// 3. Same APY and rewards per block
// 4. User reward per block = 1.9 * 10%
// = 0.019 tokens/block
// 5. Total reward for 1000 blocks = 0.019 * 1000
// = 19.25 tokens
// 4. User reward per block = 1.9 * 10% = 0.019 tokens/block
// 5. Total reward for 1000 blocks = 0.019 * 1000 = 19.25 tokens
System::set_block_number(4000);
let result4 = RewardsPallet::<Runtime>::calculate_deposit_rewards_with_lock_multiplier(
total_deposit,
Expand Down

0 comments on commit 7ecc5cb

Please sign in to comment.