From 509f5c655ba31350fb3e5022a12566b9a44ef9c2 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Thu, 22 Feb 2024 04:10:56 +0800 Subject: [PATCH 01/18] KTON Staking Part.1 --- Cargo.lock | 33 +--- pallet/account-migration/src/mock.rs | 3 + pallet/message-transact/src/mock.rs | 3 - pallet/staking/Cargo.toml | 9 +- pallet/staking/src/benchmarking.rs | 2 +- pallet/staking/src/lib.rs | 217 ++++++++++++++++-------- pallet/staking/src/mock.rs | 15 +- pallet/staking/src/tests.rs | 51 ++---- precompile/staking/src/lib.rs | 4 +- precompile/staking/src/mock.rs | 3 + precompile/staking/src/tests.rs | 1 - runtime/crab/src/pallets/staking.rs | 3 + runtime/darwinia/src/pallets/staking.rs | 7 +- runtime/pangolin/Cargo.toml | 2 +- runtime/pangolin/src/pallets/staking.rs | 3 + runtime/pangoro/src/pallets/staking.rs | 7 +- 16 files changed, 195 insertions(+), 168 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43a7329d7..fca3c7cc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3293,6 +3293,7 @@ name = "darwinia-staking" version = "6.6.0" dependencies = [ "darwinia-deposit", + "darwinia-message-transact", "darwinia-staking-traits", "dc-inflation", "dc-types", @@ -3892,19 +3893,6 @@ dependencies = [ "syn 2.0.38", ] -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime 1.3.0", - "log", - "regex", - "termcolor", -] - [[package]] name = "env_logger" version = "0.9.3" @@ -3912,7 +3900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ "atty", - "humantime 2.1.0", + "humantime", "log", "regex", "termcolor", @@ -3924,7 +3912,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ - "humantime 2.1.0", + "humantime", "is-terminal", "log", "regex", @@ -5489,15 +5477,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] - [[package]] name = "humantime" version = "2.1.0" @@ -11199,11 +11178,11 @@ dependencies = [ [[package]] name = "pretty_env_logger" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" dependencies = [ - "env_logger 0.7.1", + "env_logger 0.10.0", "log", ] diff --git a/pallet/account-migration/src/mock.rs b/pallet/account-migration/src/mock.rs index 59befed95..695de5a91 100644 --- a/pallet/account-migration/src/mock.rs +++ b/pallet/account-migration/src/mock.rs @@ -164,8 +164,11 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = (); type Kton = Dummy; + type KtonStakerAddress = (); + type KtonStakerNotifier = (); type MaxDeposits = (); type MaxUnstakings = (); + type MigrationCurve = (); type MinStakingDuration = (); type Ring = Dummy; type RuntimeEvent = RuntimeEvent; diff --git a/pallet/message-transact/src/mock.rs b/pallet/message-transact/src/mock.rs index a08fae818..4f3a4dc7e 100644 --- a/pallet/message-transact/src/mock.rs +++ b/pallet/message-transact/src/mock.rs @@ -95,14 +95,12 @@ frame_support::parameter_types! { pub const BlockGasLimit: sp_core::U256 = sp_core::U256::MAX; pub const WeightPerGas: frame_support::weights::Weight = frame_support::weights::Weight::from_parts(20_000, 0); } - pub struct FixedGasPrice; impl fp_evm::FeeCalculator for FixedGasPrice { fn min_gas_price() -> (sp_core::U256, frame_support::weights::Weight) { (sp_core::U256::from(5), frame_support::weights::Weight::zero()) } } - impl pallet_evm::Config for Runtime { type AddressMapping = pallet_evm::IdentityAddressMapping; type BlockGasLimit = BlockGasLimit; @@ -129,7 +127,6 @@ impl pallet_evm::Config for Runtime { frame_support::parameter_types! { pub const PostBlockAndTxnHashes: pallet_ethereum::PostLogContent = pallet_ethereum::PostLogContent::BlockAndTxnHashes; } - impl pallet_ethereum::Config for Runtime { type ExtraDataLength = (); type PostLogContent = PostBlockAndTxnHashes; diff --git a/pallet/staking/Cargo.toml b/pallet/staking/Cargo.toml index 6169da550..e7d4b1bc1 100644 --- a/pallet/staking/Cargo.toml +++ b/pallet/staking/Cargo.toml @@ -13,8 +13,9 @@ log = { workspace = true } scale-info = { workspace = true } # darwinia -darwinia-staking-traits = { workspace = true } -dc-types = { workspace = true } +darwinia-message-transact = { workspace = true } +darwinia-staking-traits = { workspace = true } +dc-types = { workspace = true } # darwinia optional darwinia-deposit = { workspace = true, optional = true } @@ -30,7 +31,7 @@ frame-benchmarking = { workspace = true, optional = true } [dev-dependencies] # crates.io -pretty_env_logger = { version = "0.4" } +pretty_env_logger = { version = "0.5" } # darwinia darwinia-deposit = { workspace = true, features = ["std"] } @@ -55,6 +56,7 @@ std = [ "scale-info/std", # darwinia + "darwinia-message-transact/std", "darwinia-staking-traits/std", # darwinia optional "darwinia-deposit?/std", @@ -74,6 +76,7 @@ std = [ runtime-benchmarks = [ # darwinia "darwinia-deposit", + "darwinia-message-transact/runtime-benchmarks", "darwinia-staking-traits/runtime-benchmarks", # substrate diff --git a/pallet/staking/src/benchmarking.rs b/pallet/staking/src/benchmarking.rs index 5bf7d945b..d1c31288d 100644 --- a/pallet/staking/src/benchmarking.rs +++ b/pallet/staking/src/benchmarking.rs @@ -106,7 +106,7 @@ mod benchmarks { // // The total number of deposit items has reached `Config::MaxUnstakings`. #[extrinsic_call] - _(RawOrigin::Signed(a), UNIT, UNIT, deposits); + _(RawOrigin::Signed(a), UNIT, deposits); } #[benchmark] diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index 4e4c1ca63..3f1a623c7 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -47,9 +47,12 @@ pub use weights::WeightInfo; pub use darwinia_staking_traits::*; +// core +use core::mem; // crates.io use codec::FullCodec; // darwinia +use darwinia_message_transact as _; use dc_types::{Balance, Moment}; // substrate use frame_support::{ @@ -125,6 +128,9 @@ pub mod pallet { /// Inflation and reward manager. type IssuingManager: IssuingManager; + /// KTON staker notifier. + type KtonStakerNotifier: KtonStakerNotification; + /// Pass [`pallet_session::Config::ShouldEndSession`]'s result to here. type ShouldEndSession: Get; @@ -139,6 +145,14 @@ pub mod pallet { /// Maximum unstaking/unbonding count. #[pallet::constant] type MaxUnstakings: Get; + + #[pallet::constant] + /// The curve of migration. + type MigrationCurve: Get; + + /// The address of KTON staker contract. + #[pallet::constant] + type KtonStakerAddress: Get; } #[allow(missing_docs)] @@ -311,6 +325,11 @@ pub mod pallet { #[pallet::getter(fn elapsed_time)] pub type ElapsedTime = StorageValue<_, Moment, ValueQuery>; + /// Migration starting block. + #[pallet::storage] + #[pallet::getter(fn migration_start_block)] + pub type MigrationStartBlock = StorageValue<_, BlockNumberFor, ValueQuery>; + #[derive(DefaultNoBound)] #[pallet::genesis_config] pub struct GenesisConfig { @@ -351,6 +370,12 @@ pub mod pallet { pub struct Pallet(_); #[pallet::hooks] impl Hooks> for Pallet { + fn on_runtime_upgrade() -> Weight { + >::put(>::block_number()); + + T::DbWeight::get().reads_writes(0, 1) + } + fn on_initialize(_: BlockNumberFor) -> Weight { // There are already plenty of tasks to handle during the new session, // so refrain from assigning any additional ones here. @@ -451,16 +476,12 @@ pub mod pallet { if ring_amount != 0 { Self::unstake_token::>( &mut l.staked_ring, - &mut l.unstaking_ring, + Some(&mut l.unstaking_ring), ring_amount, )?; } if kton_amount != 0 { - Self::unstake_token::>( - &mut l.staked_kton, - &mut l.unstaking_kton, - kton_amount, - )?; + Self::unstake_token::>(&mut l.staked_kton, None, kton_amount)?; } for d in deposits { @@ -481,12 +502,11 @@ pub mod pallet { pub fn restake( origin: OriginFor, ring_amount: Balance, - kton_amount: Balance, deposits: Vec>, ) -> DispatchResult { let who = ensure_signed(origin)?; - if ring_amount == 0 && kton_amount == 0 && deposits.is_empty() { + if ring_amount == 0 && deposits.is_empty() { return Ok(()); } @@ -500,13 +520,6 @@ pub mod pallet { ring_amount, )?; } - if kton_amount != 0 { - Self::restake_token::>( - &mut l.staked_kton, - &mut l.unstaking_kton, - kton_amount, - )?; - } for d in deposits { Self::restake_deposit(&who, l, d)?; @@ -669,7 +682,7 @@ pub mod pallet { fn unstake_token

( staked: &mut Balance, - unstaking: &mut BoundedVec<(Balance, BlockNumberFor), T::MaxUnstakings>, + unstaking: Option<&mut BoundedVec<(Balance, BlockNumberFor), T::MaxUnstakings>>, amount: Balance, ) -> DispatchResult where @@ -679,12 +692,13 @@ pub mod pallet { .checked_sub(amount) .ok_or("[pallet::staking] `u128` must not be overflowed; qed")?; - unstaking - .try_push(( + if let Some(u) = unstaking { + u.try_push(( amount, >::block_number() + T::MinStakingDuration::get(), )) .map_err(|_| >::ExceedMaxUnstakings)?; + } Self::update_pool::

(false, amount)?; @@ -785,26 +799,22 @@ pub mod pallet { >::try_mutate(who, |l| { let l = l.as_mut().ok_or(>::NotStaker)?; let now = >::block_number(); - let claim = |u: &mut BoundedVec<_, _>, c: &mut Balance| { - u.retain(|(a, t)| { - if t <= &now { - *c += a; - - false - } else { - true - } - }); - }; let mut r_claimed = 0; - claim(&mut l.unstaking_ring, &mut r_claimed); - ::Ring::unstake(who, r_claimed)?; - - let mut k_claimed = 0; + l.unstaking_ring.retain(|(a, t)| { + if t <= &now { + r_claimed += a; - claim(&mut l.unstaking_kton, &mut k_claimed); - ::Kton::unstake(who, k_claimed)?; + false + } else { + true + } + }); + ::Ring::unstake(who, r_claimed)?; + ::Kton::unstake( + who, + mem::take(&mut l.unstaking_kton).into_iter().fold(0, |s, (a, _)| s + a), + )?; let mut d_claimed = Vec::new(); @@ -856,14 +866,24 @@ pub mod pallet { /// Calculate the power of the given account. #[cfg(any(feature = "runtime-benchmarks", test))] pub fn quick_power_of(who: &T::AccountId) -> Power { - Self::power_of(who, >::get(), >::get()) + Self::power_of( + who, + >::get(), + >::get(), + T::MigrationCurve::get(), + ) } /// Calculate the power of the given account. /// /// This is an optimized version of [`Self::quick_power_of`]. /// Avoiding read the pools' storage multiple times. - pub fn power_of(who: &T::AccountId, ring_pool: Balance, kton_pool: Balance) -> Power { + pub fn power_of( + who: &T::AccountId, + ring_pool: Balance, + kton_pool: Balance, + migration_ratio: Perquintill, + ) -> Power { // Power is a mixture of RING and KTON. // - `total_ring_power = (amount / total_staked_ring) * HALF_POWER` // - `total_kton_power = (amount / total_staked_kton) * HALF_POWER` @@ -883,42 +903,43 @@ pub mod pallet { ) * HALF_POWER) .saturating_add( Perquintill::from_rational(l.staked_kton, kton_pool.max(1)) - * HALF_POWER, + * (migration_ratio * HALF_POWER), ) as _ }) .unwrap_or_default() } /// Distribute the session reward to staking pot and update the stakers' reward record. - pub fn distribute_session_reward(amount: Balance) -> Balance { + pub fn distribute_session_reward(amount: Balance) { + let (reward_to_v1, reward_to_v2) = { + let reward_to_ring = amount / 2; + let reward_to_kton = amount - reward_to_ring; + let reward_to_kton_v1 = T::MigrationCurve::get() * reward_to_kton; + let reward_to_kton_v2 = reward_to_kton - reward_to_kton_v1; + + (reward_to_ring + reward_to_kton_v1, reward_to_kton_v2) + }; let (sum, map) = >::take(); let staking_pot = account_id(); - let mut actual_reward = 0; - let mut unpaid = 0; - - map.into_iter().for_each(|(c, p)| { - let r = Perbill::from_rational(p, sum) * amount; + let actual_reward_v1 = map.into_iter().fold(0, |s, (c, p)| { + let r = Perbill::from_rational(p, sum) * reward_to_v1; - >::mutate(&c, |u| *u = u.map(|u| u + r).or(Some(r))); + >::mutate(c, |u| *u = u.map(|u| u + r).or(Some(r))); - // TODO: merge into one call - if T::IssuingManager::reward(&staking_pot, r).is_ok() { - actual_reward += r; + s + r + }); + let reward = |who, amount| { + if T::IssuingManager::reward(&who, amount).is_ok() { + Self::deposit_event(Event::Payout { staker: who, amount }); } else { - unpaid += r; + Self::deposit_event(Event::Unpaid { staker: who, amount }); } - }); + }; - Self::deposit_event(Event::Payout { - staker: staking_pot.clone(), - amount: actual_reward, - }); + reward(staking_pot, actual_reward_v1); + reward(T::KtonStakerAddress::get(), reward_to_v2); - if unpaid != 0 { - Self::deposit_event(Event::Unpaid { staker: staking_pot, amount: unpaid }); - } - - actual_reward + T::KtonStakerNotifier::notify(); } /// Pay the reward to the collator and its nominators. @@ -1009,6 +1030,7 @@ pub mod pallet { let nominators = >::iter().collect::>(); let ring_pool = >::get(); let kton_pool = >::get(); + let migration_ratio = T::MigrationCurve::get(); let mut collators = >::iter() .map(|(c, cm)| { let scaler = Perbill::one() - cm; @@ -1017,7 +1039,8 @@ pub mod pallet { .iter() .filter_map(|(n, c_)| { if c_ == &c { - let nominator_v = scaler * Self::power_of(n, ring_pool, kton_pool); + let nominator_v = scaler + * Self::power_of(n, ring_pool, kton_pool, migration_ratio); collator_v += nominator_v; @@ -1064,11 +1087,8 @@ where fn on_session_end() { let inflation = Self::inflate(); let reward = Self::calculate_reward(inflation); - let actual_reward = >::distribute_session_reward(reward); - if inflation != 0 { - Self::clear(inflation.saturating_sub(actual_reward)); - } + >::distribute_session_reward(reward); } /// Inflation settings. @@ -1081,9 +1101,6 @@ where /// The reward function. fn reward(who: &T::AccountId, amount: Balance) -> DispatchResult; - - /// Clear the remaining inflation. - fn clear(_remaining: Balance) {} } impl IssuingManager for () where @@ -1153,7 +1170,7 @@ where /// A snapshot of the stake backing a single collator in the system. #[cfg_attr(test, derive(Clone))] -#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebug)] +#[derive(Encode, Decode, TypeInfo, RuntimeDebug)] pub struct Exposure { /// The commission of this collator. pub commission: Perbill, @@ -1164,7 +1181,7 @@ pub struct Exposure { } /// A snapshot of the staker's state. #[cfg_attr(test, derive(Clone))] -#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebug)] +#[derive(Encode, Decode, TypeInfo, RuntimeDebug)] pub struct IndividualExposure { /// Nominator. pub who: AccountId, @@ -1208,3 +1225,65 @@ where { PalletId(*b"da/staki").into_account_truncating() } + +/// The address of the KTON staker contract. +/// ``` +/// b"sc/ktstk" +/// ``` +pub struct KtonStakerAddress; +impl Get for KtonStakerAddress +where + T: From<[u8; 20]>, +{ + fn get() -> T { + [115, 99, 47, 107, 116, 115, 116, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].into() + } +} + +/// A curve helps to migrate to staking v2 smoothly. +pub struct MigrationCurve(PhantomData); +#[cfg(not(any(feature = "runtime-benchmarks", test)))] +impl Get for MigrationCurve +where + T: Config, +{ + fn get() -> Perquintill { + // substrate + use sp_runtime::traits::SaturatedConversion; + + let x = (>::block_number() - >::get()) + .saturated_into::() + .max(1); + let month_in_blocks = 30 * 24 * 60 * 60 / 12; + + Perquintill::one() - Perquintill::from_rational(x, month_in_blocks) + } +} +#[cfg(any(feature = "runtime-benchmarks", test))] +impl Get for MigrationCurve +where + T: Config, +{ + fn get() -> Perquintill { + Perquintill::one() + } +} + +/// KTON staker contact notification interface. +pub trait KtonStakerNotification { + /// Notify the KTON staker contract. + fn notify() {} +} +impl KtonStakerNotification for () {} +/// KTON staker contact notifier. +pub struct KtonStakerNotifier(PhantomData); +impl KtonStakerNotification for KtonStakerNotifier +where + T: darwinia_message_transact::Config, +{ + fn notify() { + // if let Err(e) = darwinia_message_transact::Pallet::message_transact() { + // log::error!("[pallet::staking] failed to notify KTON staker contract due to {:?}", e); + // } + } +} diff --git a/pallet/staking/src/mock.rs b/pallet/staking/src/mock.rs index 8c16c2943..c76ecd3f0 100644 --- a/pallet/staking/src/mock.rs +++ b/pallet/staking/src/mock.rs @@ -282,14 +282,6 @@ impl darwinia_staking::IssuingManager for StatedOnSessionEnd { OnCrabSessionEnd::reward(who, amount) } } - - fn clear(remaining: Balance) { - if INFLATION_TYPE.with(|v| *v.borrow()) == 0 { - OnDarwiniaSessionEnd::clear(remaining) - } else { - OnCrabSessionEnd::clear(remaining) - } - } } pub enum OnDarwiniaSessionEnd {} impl darwinia_staking::IssuingManager for OnDarwiniaSessionEnd { @@ -316,10 +308,6 @@ impl darwinia_staking::IssuingManager for OnDarwiniaSessionEnd { Ok(()) } - - fn clear(remaining: Balance) { - let _ = Balances::deposit_into_existing(&Treasury::account_id(), remaining); - } } pub enum OnCrabSessionEnd {} impl darwinia_staking::IssuingManager for OnCrabSessionEnd { @@ -354,6 +342,9 @@ impl darwinia_staking::Config for Runtime { type Kton = KtonStaking; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = frame_support::traits::ConstU32<16>; + type KtonStakerAddress = (); + type KtonStakerNotifier = (); + type MigrationCurve = darwinia_staking::MigrationCurve; type MinStakingDuration = frame_support::traits::ConstU64<3>; type Ring = RingStaking; type RuntimeEvent = RuntimeEvent; diff --git a/pallet/staking/src/tests.rs b/pallet/staking/src/tests.rs index a78154eed..f620df07f 100644 --- a/pallet/staking/src/tests.rs +++ b/pallet/staking/src/tests.rs @@ -21,7 +21,7 @@ use core::time::Duration; // darwinia use crate::{mock::*, *}; use darwinia_deposit::Error as DepositError; -use dc_types::{Balance, UNIT}; +use dc_types::UNIT; // substrate use frame_support::{assert_noop, assert_ok, BoundedVec}; use sp_runtime::{assert_eq_error_rate, DispatchError, Perbill}; @@ -219,7 +219,6 @@ fn unstake_should_work() { staked_kton: 2 * UNIT, staked_deposits: BoundedVec::truncate_from(vec![0, 1, 2]), unstaking_ring: BoundedVec::truncate_from(vec![(UNIT, 6)]), - unstaking_kton: BoundedVec::truncate_from(vec![(UNIT, 7)]), ..ZeroDefault::default() } ); @@ -240,8 +239,8 @@ fn unstake_should_work() { staked_kton: 2 * UNIT, staked_deposits: BoundedVec::truncate_from(vec![0, 2]), unstaking_ring: BoundedVec::truncate_from(vec![(UNIT, 6)]), - unstaking_kton: BoundedVec::truncate_from(vec![(UNIT, 7)]), - unstaking_deposits: BoundedVec::truncate_from(vec![(1, 8)]) + unstaking_deposits: BoundedVec::truncate_from(vec![(1, 8)]), + ..ZeroDefault::default() } ); @@ -252,7 +251,6 @@ fn unstake_should_work() { Staking::ledger_of(1).unwrap(), Ledger { unstaking_ring: BoundedVec::truncate_from(vec![(UNIT, 6), (2 * UNIT, 9)]), - unstaking_kton: BoundedVec::truncate_from(vec![(UNIT, 7), (2 * UNIT, 9)]), unstaking_deposits: BoundedVec::truncate_from(vec![(1, 8), (0, 9), (2, 9)]), ..ZeroDefault::default() } @@ -282,34 +280,18 @@ fn restake_should_work() { Staking::ledger_of(1).unwrap(), Ledger { unstaking_ring: BoundedVec::truncate_from(vec![(UNIT, 6), (UNIT, 7), (UNIT, 8)]), - unstaking_kton: BoundedVec::truncate_from(vec![(UNIT, 6), (UNIT, 7), (UNIT, 8)]), unstaking_deposits: BoundedVec::truncate_from(vec![(0, 6), (1, 6), (2, 6)]), ..ZeroDefault::default() } ); // Restake 1.5 RING. - assert_ok!(Staking::restake(RuntimeOrigin::signed(1), 3 * UNIT / 2, 0, Vec::new())); + assert_ok!(Staking::restake(RuntimeOrigin::signed(1), 3 * UNIT / 2, Vec::new())); assert_eq!( Staking::ledger_of(1).unwrap(), Ledger { staked_ring: 3 * UNIT / 2, unstaking_ring: BoundedVec::truncate_from(vec![(UNIT, 6), (UNIT / 2, 7)]), - unstaking_kton: BoundedVec::truncate_from(vec![(UNIT, 6), (UNIT, 7), (UNIT, 8)]), - unstaking_deposits: BoundedVec::truncate_from(vec![(0, 6), (1, 6), (2, 6)]), - ..ZeroDefault::default() - } - ); - - // Restake 1.5 KTON. - assert_ok!(Staking::restake(RuntimeOrigin::signed(1), 0, 3 * UNIT / 2, Vec::new())); - assert_eq!( - Staking::ledger_of(1).unwrap(), - Ledger { - staked_ring: 3 * UNIT / 2, - staked_kton: 3 * UNIT / 2, - unstaking_ring: BoundedVec::truncate_from(vec![(UNIT, 6), (UNIT / 2, 7)]), - unstaking_kton: BoundedVec::truncate_from(vec![(UNIT, 6), (UNIT / 2, 7)]), unstaking_deposits: BoundedVec::truncate_from(vec![(0, 6), (1, 6), (2, 6)]), ..ZeroDefault::default() } @@ -322,32 +304,25 @@ fn restake_should_work() { ); // Restake 1 deposit. - assert_ok!(Staking::restake(RuntimeOrigin::signed(1), 0, 0, vec![1])); + assert_ok!(Staking::restake(RuntimeOrigin::signed(1), 0, vec![1])); assert_eq!( Staking::ledger_of(1).unwrap(), Ledger { staked_ring: 3 * UNIT / 2, - staked_kton: 3 * UNIT / 2, staked_deposits: BoundedVec::truncate_from(vec![1]), unstaking_ring: BoundedVec::truncate_from(vec![(UNIT, 6), (UNIT / 2, 7)]), - unstaking_kton: BoundedVec::truncate_from(vec![(UNIT, 6), (UNIT / 2, 7)]), unstaking_deposits: BoundedVec::truncate_from(vec![(0, 6), (2, 6)]), + ..ZeroDefault::default() } ); - // Restake 1.5 RING, 1.5 KTON and 2 deposits. + // Restake 1.5 RING and 2 deposits. Efflux::block(1); - assert_ok!(Staking::restake( - RuntimeOrigin::signed(1), - 3 * UNIT / 2, - 3 * UNIT / 2, - vec![0, 2] - )); + assert_ok!(Staking::restake(RuntimeOrigin::signed(1), 3 * UNIT / 2, vec![0, 2])); assert_eq!( Staking::ledger_of(1).unwrap(), Ledger { staked_ring: 3 * UNIT, - staked_kton: 3 * UNIT, staked_deposits: BoundedVec::truncate_from(vec![1, 0, 2]), ..ZeroDefault::default() } @@ -376,7 +351,6 @@ fn claim_should_work() { Staking::ledger_of(1).unwrap(), Ledger { unstaking_ring: BoundedVec::truncate_from(vec![(UNIT, 6), (UNIT, 9)]), - unstaking_kton: BoundedVec::truncate_from(vec![(UNIT, 7), (UNIT, 9)]), unstaking_deposits: BoundedVec::truncate_from(vec![(0, 8), (1, 9), (2, 9)]), ..ZeroDefault::default() } @@ -390,7 +364,6 @@ fn claim_should_work() { Staking::ledger_of(1).unwrap(), Ledger { unstaking_ring: BoundedVec::truncate_from(vec![(UNIT, 9)]), - unstaking_kton: BoundedVec::truncate_from(vec![(UNIT, 7), (UNIT, 9)]), unstaking_deposits: BoundedVec::truncate_from(vec![(0, 8), (1, 9), (2, 9)]), ..ZeroDefault::default() } @@ -400,12 +373,11 @@ fn claim_should_work() { Efflux::block(1); assert_ok!(Staking::claim(RuntimeOrigin::signed(1))); assert_eq!(System::account(1).consumers, 2); - assert_eq!(Assets::balance(0, 1), 999 * UNIT + 22_842_639_593_907); + assert_eq!(Assets::balance(0, 1), 998 * UNIT + 22_842_639_593_907); assert_eq!( Staking::ledger_of(1).unwrap(), Ledger { unstaking_ring: BoundedVec::truncate_from(vec![(UNIT, 9)]), - unstaking_kton: BoundedVec::truncate_from(vec![(UNIT, 9)]), unstaking_deposits: BoundedVec::truncate_from(vec![(0, 8), (1, 9), (2, 9)]), ..ZeroDefault::default() } @@ -415,12 +387,11 @@ fn claim_should_work() { Efflux::block(1); assert_ok!(Staking::claim(RuntimeOrigin::signed(1))); assert_eq!(System::account(1).consumers, 2); - assert_eq!(Assets::balance(0, 1), 999 * UNIT + 22_842_639_593_907); + assert_eq!(Assets::balance(0, 1), 998 * UNIT + 22_842_639_593_907); assert_eq!( Staking::ledger_of(1).unwrap(), Ledger { unstaking_ring: BoundedVec::truncate_from(vec![(UNIT, 9)]), - unstaking_kton: BoundedVec::truncate_from(vec![(UNIT, 9)]), unstaking_deposits: BoundedVec::truncate_from(vec![(1, 9), (2, 9)]), ..ZeroDefault::default() } @@ -431,7 +402,7 @@ fn claim_should_work() { assert_ok!(Staking::claim(RuntimeOrigin::signed(1))); assert_eq!(System::account(1).consumers, 1); assert_eq!(Balances::free_balance(1), 997 * UNIT); - assert_eq!(Assets::balance(0, 1), 1_000 * UNIT + 22_842_639_593_907); + assert_eq!(Assets::balance(0, 1), 998 * UNIT + 22_842_639_593_907); assert!(Staking::ledger_of(1).is_none()); }); } diff --git a/precompile/staking/src/lib.rs b/precompile/staking/src/lib.rs index 5d655b6e4..8afc8b8ae 100644 --- a/precompile/staking/src/lib.rs +++ b/precompile/staking/src/lib.rs @@ -97,11 +97,10 @@ where Ok(true) } - #[precompile::public("restake(uint256,uint256,uint8[])")] + #[precompile::public("restake(uint256,uint8[])")] fn restake( handle: &mut impl PrecompileHandle, ring_amount: U256, - kton_amount: U256, deposits: Vec, ) -> EvmResult { let origin = handle.context().caller.into(); @@ -112,7 +111,6 @@ where Some(origin).into(), darwinia_staking::Call::::restake { ring_amount: ring_amount.as_u128(), - kton_amount: kton_amount.as_u128(), deposits, }, )?; diff --git a/precompile/staking/src/mock.rs b/precompile/staking/src/mock.rs index aba2a5b6c..a961ae333 100644 --- a/precompile/staking/src/mock.rs +++ b/precompile/staking/src/mock.rs @@ -236,8 +236,11 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = (); type Kton = KtonStaking; + type KtonStakerAddress = (); + type KtonStakerNotifier = (); type MaxDeposits = ::MaxDeposits; type MaxUnstakings = frame_support::traits::ConstU32<16>; + type MigrationCurve = darwinia_staking::MigrationCurve; type MinStakingDuration = frame_support::traits::ConstU64<3>; type Ring = RingStaking; type RuntimeEvent = RuntimeEvent; diff --git a/precompile/staking/src/tests.rs b/precompile/staking/src/tests.rs index 4b3d32e28..97df00530 100644 --- a/precompile/staking/src/tests.rs +++ b/precompile/staking/src/tests.rs @@ -83,7 +83,6 @@ fn stake_unstake_restake() { Precompile, PCall::restake { ring_amount: 200.into(), - kton_amount: U256::zero(), deposits: vec![], }, ) diff --git a/runtime/crab/src/pallets/staking.rs b/runtime/crab/src/pallets/staking.rs index 6a617aefa..55d394423 100644 --- a/runtime/crab/src/pallets/staking.rs +++ b/runtime/crab/src/pallets/staking.rs @@ -105,8 +105,11 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = OnCrabSessionEnd; type Kton = KtonStaking; + type KtonStakerAddress = darwinia_staking::KtonStakerAddress; + type KtonStakerNotifier = darwinia_staking::KtonStakerNotifier; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = ConstU32<16>; + type MigrationCurve = darwinia_staking::MigrationCurve; type MinStakingDuration = MinStakingDuration; type Ring = RingStaking; type RuntimeEvent = RuntimeEvent; diff --git a/runtime/darwinia/src/pallets/staking.rs b/runtime/darwinia/src/pallets/staking.rs index 785e19d53..eeb53fc32 100644 --- a/runtime/darwinia/src/pallets/staking.rs +++ b/runtime/darwinia/src/pallets/staking.rs @@ -97,10 +97,6 @@ impl darwinia_staking::IssuingManager for OnDarwiniaSessionEnd { Ok(()) } - - fn clear(remaining: Balance) { - let _ = Balances::deposit_into_existing(&Treasury::account_id(), remaining); - } } pub enum ShouldEndSession {} @@ -120,8 +116,11 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = OnDarwiniaSessionEnd; type Kton = KtonStaking; + type KtonStakerAddress = darwinia_staking::KtonStakerAddress; + type KtonStakerNotifier = darwinia_staking::KtonStakerNotifier; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = ConstU32<16>; + type MigrationCurve = darwinia_staking::MigrationCurve; type MinStakingDuration = MinStakingDuration; type Ring = RingStaking; type RuntimeEvent = RuntimeEvent; diff --git a/runtime/pangolin/Cargo.toml b/runtime/pangolin/Cargo.toml index d93cdddc4..6553072b7 100644 --- a/runtime/pangolin/Cargo.toml +++ b/runtime/pangolin/Cargo.toml @@ -254,8 +254,8 @@ std = [ "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", "pallet-treasury/std", - "pallet-utility/std", "pallet-tx-pause/std", + "pallet-utility/std", "pallet-whitelist/std", "sp-api/std", "sp-block-builder/std", diff --git a/runtime/pangolin/src/pallets/staking.rs b/runtime/pangolin/src/pallets/staking.rs index bdc9a2bfd..76eebfbb0 100644 --- a/runtime/pangolin/src/pallets/staking.rs +++ b/runtime/pangolin/src/pallets/staking.rs @@ -99,8 +99,11 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = OnPangolinSessionEnd; type Kton = KtonStaking; + type KtonStakerAddress = darwinia_staking::KtonStakerAddress; + type KtonStakerNotifier = darwinia_staking::KtonStakerNotifier; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = ConstU32<16>; + type MigrationCurve = darwinia_staking::MigrationCurve; type MinStakingDuration = ConstU32<{ 2 * MINUTES }>; type Ring = RingStaking; type RuntimeEvent = RuntimeEvent; diff --git a/runtime/pangoro/src/pallets/staking.rs b/runtime/pangoro/src/pallets/staking.rs index 242dfc9c4..ba184b6d0 100644 --- a/runtime/pangoro/src/pallets/staking.rs +++ b/runtime/pangoro/src/pallets/staking.rs @@ -93,10 +93,6 @@ impl darwinia_staking::IssuingManager for OnPangoroSessionEnd { Ok(()) } - - fn clear(remaining: Balance) { - let _ = Balances::deposit_into_existing(&Treasury::account_id(), remaining); - } } pub enum ShouldEndSession {} @@ -116,8 +112,11 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = OnPangoroSessionEnd; type Kton = KtonStaking; + type KtonStakerAddress = darwinia_staking::KtonStakerAddress; + type KtonStakerNotifier = darwinia_staking::KtonStakerNotifier; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = ConstU32<16>; + type MigrationCurve = darwinia_staking::MigrationCurve; type MinStakingDuration = ConstU32<{ 10 * MINUTES }>; type Ring = RingStaking; type RuntimeEvent = RuntimeEvent; From 47718c9ab00ba2dc76e4e7256b7257a2c79b12e4 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Thu, 22 Feb 2024 04:30:15 +0800 Subject: [PATCH 02/18] More tests --- pallet/staking/src/lib.rs | 10 ---------- pallet/staking/src/mock.rs | 7 ++++--- pallet/staking/src/tests.rs | 29 ++++++++++++++++++++++++++++- precompile/staking/src/mock.rs | 2 +- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index 3f1a623c7..97d2a1cb8 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -1242,7 +1242,6 @@ where /// A curve helps to migrate to staking v2 smoothly. pub struct MigrationCurve(PhantomData); -#[cfg(not(any(feature = "runtime-benchmarks", test)))] impl Get for MigrationCurve where T: Config, @@ -1259,15 +1258,6 @@ where Perquintill::one() - Perquintill::from_rational(x, month_in_blocks) } } -#[cfg(any(feature = "runtime-benchmarks", test))] -impl Get for MigrationCurve -where - T: Config, -{ - fn get() -> Perquintill { - Perquintill::one() - } -} /// KTON staker contact notification interface. pub trait KtonStakerNotification { diff --git a/pallet/staking/src/mock.rs b/pallet/staking/src/mock.rs index c76ecd3f0..a00e3adda 100644 --- a/pallet/staking/src/mock.rs +++ b/pallet/staking/src/mock.rs @@ -232,6 +232,7 @@ impl pallet_treasury::Config for Runtime { frame_support::parameter_types! { pub PayoutFraction: sp_runtime::Perbill = sp_runtime::Perbill::from_percent(40); + pub MigrationCurve: sp_runtime::Perquintill = sp_runtime::Perquintill::one(); pub static InflationType: u8 = 0; } pub enum KtonStaking {} @@ -340,11 +341,11 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = StatedOnSessionEnd; type Kton = KtonStaking; - type MaxDeposits = ::MaxDeposits; - type MaxUnstakings = frame_support::traits::ConstU32<16>; type KtonStakerAddress = (); type KtonStakerNotifier = (); - type MigrationCurve = darwinia_staking::MigrationCurve; + type MaxDeposits = ::MaxDeposits; + type MaxUnstakings = frame_support::traits::ConstU32<16>; + type MigrationCurve = MigrationCurve; type MinStakingDuration = frame_support::traits::ConstU64<3>; type Ring = RingStaking; type RuntimeEvent = RuntimeEvent; diff --git a/pallet/staking/src/tests.rs b/pallet/staking/src/tests.rs index f620df07f..4f3dba5d8 100644 --- a/pallet/staking/src/tests.rs +++ b/pallet/staking/src/tests.rs @@ -19,7 +19,7 @@ // core use core::time::Duration; // darwinia -use crate::{mock::*, *}; +use crate::{mock::*, MigrationCurve, *}; use darwinia_deposit::Error as DepositError; use dc_types::UNIT; // substrate @@ -863,3 +863,30 @@ fn on_new_session_should_work() { ); }); } + +#[test] +fn migration_curve_should_work() { + ExtBuilder::default().build().execute_with(|| { + System::set_block_number(10); + >::put(10); + + assert_eq!( + vec![1, 7, 14, 21, 29, 30] + .into_iter() + .map(|x| { + System::set_block_number(10 + x * 24 * 60 * 60 / 12); + + format!("{:?}", >::get()) + }) + .collect::>(), + [ + "96.6666666666666667%", + "76.6666666666666667%", + "53.3333333333333334%", + "30%", + "3.3333333333333334%", + "0%" + ] + ); + }); +} diff --git a/precompile/staking/src/mock.rs b/precompile/staking/src/mock.rs index a961ae333..51f2ece5e 100644 --- a/precompile/staking/src/mock.rs +++ b/precompile/staking/src/mock.rs @@ -240,7 +240,7 @@ impl darwinia_staking::Config for Runtime { type KtonStakerNotifier = (); type MaxDeposits = ::MaxDeposits; type MaxUnstakings = frame_support::traits::ConstU32<16>; - type MigrationCurve = darwinia_staking::MigrationCurve; + type MigrationCurve = (); type MinStakingDuration = frame_support::traits::ConstU64<3>; type Ring = RingStaking; type RuntimeEvent = RuntimeEvent; From 24a28c28a4ae952ece97b5310b6e095c8b93e979 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Thu, 22 Feb 2024 04:32:35 +0800 Subject: [PATCH 03/18] Format --- precompile/staking/src/tests.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/precompile/staking/src/tests.rs b/precompile/staking/src/tests.rs index 97df00530..82a4799c6 100644 --- a/precompile/staking/src/tests.rs +++ b/precompile/staking/src/tests.rs @@ -81,10 +81,7 @@ fn stake_unstake_restake() { .prepare_test( alice, Precompile, - PCall::restake { - ring_amount: 200.into(), - deposits: vec![], - }, + PCall::restake { ring_amount: 200.into(), deposits: vec![] }, ) .execute_returns(true); assert_eq!(Staking::ledger_of(alice).unwrap().staked_ring, 200); From 26d4d5052cf92c81c8a03cae14feb4c00acc2a25 Mon Sep 17 00:00:00 2001 From: bear Date: Thu, 22 Feb 2024 13:33:51 +0800 Subject: [PATCH 04/18] Fix staking precompile test --- precompile/metadata/abi/staking.json | 10 ++-------- precompile/metadata/sol/staking.sol | 2 -- precompile/staking/src/tests.rs | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/precompile/metadata/abi/staking.json b/precompile/metadata/abi/staking.json index 1b40504d7..5c7f8a400 100644 --- a/precompile/metadata/abi/staking.json +++ b/precompile/metadata/abi/staking.json @@ -104,11 +104,6 @@ "name": "ringAmount", "type": "uint256" }, - { - "internalType": "uint256", - "name": "ktonAmount", - "type": "uint256" - }, { "internalType": "uint8[]", "name": "depositIds", @@ -247,13 +242,12 @@ "_0": "returns true on success, false otherwise." } }, - "restake(uint256,uint256,uint8[])": + "restake(uint256,uint8[])": { "details": "Re-stake the unstaking assets immediately.", "params": { "depositIds": "The deposit ids list", - "ktonAmount": "The amount of staking KTON asset", "ringAmount": "The amount of staking RING asset" }, "returns": @@ -300,7 +294,7 @@ "collect(uint32)": "10a66536", "nominate(address)": "b332180b", "payout(address)": "0b7e9c44", - "restake(uint256,uint256,uint8[])": "17092fcb", + "restake(uint256,uint8[])": "6dbcd550", "stake(uint256,uint256,uint8[])": "757f9b3b", "unstake(uint256,uint256,uint8[])": "ef20fcb3" } diff --git a/precompile/metadata/sol/staking.sol b/precompile/metadata/sol/staking.sol index 1ca95a180..6deec0a74 100644 --- a/precompile/metadata/sol/staking.sol +++ b/precompile/metadata/sol/staking.sol @@ -51,12 +51,10 @@ interface Staking { /// @dev Re-stake the unstaking assets immediately. /// @param ringAmount The amount of staking RING asset - /// @param ktonAmount The amount of staking KTON asset /// @param depositIds The deposit ids list /// @return true on success, false otherwise. function restake( uint256 ringAmount, - uint256 ktonAmount, uint8[] memory depositIds ) external returns (bool); diff --git a/precompile/staking/src/tests.rs b/precompile/staking/src/tests.rs index 82a4799c6..71aeb568a 100644 --- a/precompile/staking/src/tests.rs +++ b/precompile/staking/src/tests.rs @@ -35,7 +35,7 @@ fn precompiles() -> TestPrecompiles { fn selectors() { assert!(PCall::stake_selectors().contains(&0x757f9b3b)); assert!(PCall::unstake_selectors().contains(&0xef20fcb3)); - assert!(PCall::restake_selectors().contains(&0x17092fcb)); + assert!(PCall::restake_selectors().contains(&0x6dbcd550)); assert!(PCall::claim_selectors().contains(&0x4e71d92d)); assert!(PCall::nominate_selectors().contains(&0xb332180b)); assert!(PCall::collect_selectors().contains(&0x10a66536)); From 056bce99c56503d01e1d06fb02585b0f35d79c5d Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Thu, 22 Feb 2024 16:55:03 +0800 Subject: [PATCH 05/18] Test --- pallet/staking/src/tests.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pallet/staking/src/tests.rs b/pallet/staking/src/tests.rs index 4f3dba5d8..54549b50d 100644 --- a/pallet/staking/src/tests.rs +++ b/pallet/staking/src/tests.rs @@ -871,7 +871,7 @@ fn migration_curve_should_work() { >::put(10); assert_eq!( - vec![1, 7, 14, 21, 29, 30] + vec![0, 1, 7, 14, 21, 29, 30, 31, 999] .into_iter() .map(|x| { System::set_block_number(10 + x * 24 * 60 * 60 / 12); @@ -880,12 +880,15 @@ fn migration_curve_should_work() { }) .collect::>(), [ + "99.9995370370370371%", "96.6666666666666667%", "76.6666666666666667%", "53.3333333333333334%", "30%", "3.3333333333333334%", - "0%" + "0%", + "0%", + "0%", ] ); }); From f0457808c4d69b3da8b70ddbf1f6596ec19ae129 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Thu, 22 Feb 2024 16:57:00 +0800 Subject: [PATCH 06/18] Transfer back --- pallet/staking/src/lib.rs | 1 + pallet/staking/src/tests.rs | 9 +++------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index 97d2a1cb8..ec1cff239 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -482,6 +482,7 @@ pub mod pallet { } if kton_amount != 0 { Self::unstake_token::>(&mut l.staked_kton, None, kton_amount)?; + T::Kton::unstake(&who, kton_amount)?; } for d in deposits { diff --git a/pallet/staking/src/tests.rs b/pallet/staking/src/tests.rs index 54549b50d..ef0f2c114 100644 --- a/pallet/staking/src/tests.rs +++ b/pallet/staking/src/tests.rs @@ -258,7 +258,7 @@ fn unstake_should_work() { // Keep the stakes for at least `MinStakingDuration`. assert_eq!(Balances::free_balance(1), 994 * UNIT); - assert_eq!(Assets::balance(0, 1), 997 * UNIT + 22_842_639_593_907); + assert_eq!(Assets::balance(0, 1), 1_000 * UNIT + 22_842_639_593_907); }); } @@ -275,7 +275,7 @@ fn restake_should_work() { Efflux::block(1); assert_ok!(Staking::unstake(RuntimeOrigin::signed(1), UNIT, UNIT, Vec::new())); assert_eq!(Balances::free_balance(1), 994 * UNIT); - assert_eq!(Assets::balance(0, 1), 997 * UNIT + 22_842_639_593_907); + assert_eq!(Assets::balance(0, 1), 1_000 * UNIT + 22_842_639_593_907); assert_eq!( Staking::ledger_of(1).unwrap(), Ledger { @@ -346,7 +346,7 @@ fn claim_should_work() { Efflux::block(1); assert_ok!(Staking::unstake(RuntimeOrigin::signed(1), UNIT, UNIT, vec![1, 2])); assert_eq!(Balances::free_balance(1), 995 * UNIT); - assert_eq!(Assets::balance(0, 1), 998 * UNIT + 22_842_639_593_907); + assert_eq!(Assets::balance(0, 1), 1_000 * UNIT + 22_842_639_593_907); assert_eq!( Staking::ledger_of(1).unwrap(), Ledger { @@ -373,7 +373,6 @@ fn claim_should_work() { Efflux::block(1); assert_ok!(Staking::claim(RuntimeOrigin::signed(1))); assert_eq!(System::account(1).consumers, 2); - assert_eq!(Assets::balance(0, 1), 998 * UNIT + 22_842_639_593_907); assert_eq!( Staking::ledger_of(1).unwrap(), Ledger { @@ -387,7 +386,6 @@ fn claim_should_work() { Efflux::block(1); assert_ok!(Staking::claim(RuntimeOrigin::signed(1))); assert_eq!(System::account(1).consumers, 2); - assert_eq!(Assets::balance(0, 1), 998 * UNIT + 22_842_639_593_907); assert_eq!( Staking::ledger_of(1).unwrap(), Ledger { @@ -402,7 +400,6 @@ fn claim_should_work() { assert_ok!(Staking::claim(RuntimeOrigin::signed(1))); assert_eq!(System::account(1).consumers, 1); assert_eq!(Balances::free_balance(1), 997 * UNIT); - assert_eq!(Assets::balance(0, 1), 998 * UNIT + 22_842_639_593_907); assert!(Staking::ledger_of(1).is_none()); }); } From e8d820f8f914266bd5b171fb441a6e39bd538209 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Thu, 22 Feb 2024 17:39:01 +0800 Subject: [PATCH 07/18] Optimize curve --- pallet/staking/src/lib.rs | 12 +++++++++++- pallet/staking/src/tests.rs | 25 ++++++++++++++----------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index ec1cff239..b181cafb0 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -915,7 +915,11 @@ pub mod pallet { let (reward_to_v1, reward_to_v2) = { let reward_to_ring = amount / 2; let reward_to_kton = amount - reward_to_ring; - let reward_to_kton_v1 = T::MigrationCurve::get() * reward_to_kton; + #[cfg(not(any(test, feature = "runtime-benchmarks")))] + let ratio = migration_curve_kton_reward(T::MigrationCurve::get()); + #[cfg(any(test, feature = "runtime-benchmarks"))] + let ratio = Perquintill::one(); + let reward_to_kton_v1 = ratio * reward_to_kton; let reward_to_kton_v2 = reward_to_kton - reward_to_kton_v1; (reward_to_ring + reward_to_kton_v1, reward_to_kton_v2) @@ -1259,6 +1263,12 @@ where Perquintill::one() - Perquintill::from_rational(x, month_in_blocks) } } +/// The KTON reward curve during migrating to staking v2. +pub fn migration_curve_kton_reward(x: Perquintill) -> Perquintill { + let x = x.deconstruct(); + + Perquintill::from_rational(x, x + Perquintill::one().deconstruct()) +} /// KTON staker contact notification interface. pub trait KtonStakerNotification { diff --git a/pallet/staking/src/tests.rs b/pallet/staking/src/tests.rs index ef0f2c114..3bf72c593 100644 --- a/pallet/staking/src/tests.rs +++ b/pallet/staking/src/tests.rs @@ -862,7 +862,7 @@ fn on_new_session_should_work() { } #[test] -fn migration_curve_should_work() { +fn migration_curves_should_work() { ExtBuilder::default().build().execute_with(|| { System::set_block_number(10); >::put(10); @@ -873,19 +873,22 @@ fn migration_curve_should_work() { .map(|x| { System::set_block_number(10 + x * 24 * 60 * 60 / 12); - format!("{:?}", >::get()) + let x = >::get(); + let y = migration_curve_kton_reward(x); + + format!("{x:?} -> {y:?}") }) .collect::>(), [ - "99.9995370370370371%", - "96.6666666666666667%", - "76.6666666666666667%", - "53.3333333333333334%", - "30%", - "3.3333333333333334%", - "0%", - "0%", - "0%", + "99.9995370370370371% -> 49.9998842589913402%", + "96.6666666666666667% -> 49.1525423728813559%", + "76.6666666666666667% -> 43.3962264150943396%", + "53.3333333333333334% -> 34.7826086956521739%", + "30% -> 23.0769230769230769%", + "3.3333333333333334% -> 3.2258064516129032%", + "0% -> 0%", + "0% -> 0%", + "0% -> 0%" ] ); }); From 7b711dd352a7d88211d48bd318c4f9bad6ceb8f1 Mon Sep 17 00:00:00 2001 From: Bear Wang Date: Thu, 22 Feb 2024 17:45:47 +0800 Subject: [PATCH 08/18] Complete staking notify hook (#1410) * Add notify impl * Polish the implementation * Add to field * Add first params * Add comment --- Cargo.lock | 3 ++ pallet/staking/Cargo.toml | 7 ++++- pallet/staking/src/lib.rs | 60 +++++++++++++++++++++++++++++++++---- pallet/staking/src/tests.rs | 16 ++++++++++ 4 files changed, 80 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fca3c7cc9..29dca9c93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3292,11 +3292,14 @@ dependencies = [ name = "darwinia-staking" version = "6.6.0" dependencies = [ + "array-bytes", "darwinia-deposit", "darwinia-message-transact", "darwinia-staking-traits", "dc-inflation", "dc-types", + "ethabi", + "ethereum", "frame-benchmarking", "frame-support", "frame-system", diff --git a/pallet/staking/Cargo.toml b/pallet/staking/Cargo.toml index e7d4b1bc1..57262c994 100644 --- a/pallet/staking/Cargo.toml +++ b/pallet/staking/Cargo.toml @@ -8,9 +8,12 @@ version.workspace = true [dependencies] # crates.io +array-bytes = { workspace = true } +ethereum = { workspace = true } codec = { workspace = true, package = "parity-scale-codec" } log = { workspace = true } scale-info = { workspace = true } +ethabi = { version = "18.0", default-features = false } # darwinia darwinia-message-transact = { workspace = true } @@ -26,6 +29,7 @@ pallet-authorship = { workspace = true } pallet-session = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } +sp-core = { workspace = true } # substrate optional frame-benchmarking = { workspace = true, optional = true } @@ -43,7 +47,6 @@ pallet-balances = { workspace = true, features = ["std"] } pallet-session = { workspace = true, features = ["std"] } pallet-timestamp = { workspace = true, features = ["std"] } pallet-treasury = { workspace = true, features = ["std"] } -sp-core = { workspace = true, features = ["std"] } sp-io = { workspace = true, features = ["std"] } substrate-test-utils = { workspace = true } @@ -53,6 +56,7 @@ std = [ # crates.io "codec/std", "log/std", + "ethabi/std", "scale-info/std", # darwinia @@ -69,6 +73,7 @@ std = [ "pallet-session/std", "sp-runtime/std", "sp-std/std", + "sp-core/std", # substrate optional "frame-benchmarking?/std", ] diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index b181cafb0..252074237 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -51,14 +51,19 @@ pub use darwinia_staking_traits::*; use core::mem; // crates.io use codec::FullCodec; +use ethabi::Token; +use ethereum::{ + LegacyTransaction, TransactionAction, TransactionSignature, TransactionV2 as Transaction, +}; // darwinia -use darwinia_message_transact as _; +use darwinia_message_transact::LcmpEthOrigin; use dc_types::{Balance, Moment}; // substrate use frame_support::{ pallet_prelude::*, traits::Currency, DefaultNoBound, EqNoBound, PalletId, PartialEqNoBound, }; use frame_system::{pallet_prelude::*, RawOrigin}; +use sp_core::{H160, U256}; use sp_runtime::{ traits::{AccountIdConversion, Convert, One, Zero}, Perbill, Perquintill, @@ -1280,11 +1285,56 @@ impl KtonStakerNotification for () {} pub struct KtonStakerNotifier(PhantomData); impl KtonStakerNotification for KtonStakerNotifier where - T: darwinia_message_transact::Config, + T: darwinia_message_transact::Config + Config, + T::RuntimeOrigin: Into> + From, + ::AccountId: Into, { fn notify() { - // if let Err(e) = darwinia_message_transact::Pallet::message_transact() { - // log::error!("[pallet::staking] failed to notify KTON staker contract due to {:?}", e); - // } + // Should be a valid mock signature, copied from https://github.com/rust-ethereum/ethereum/blob/master/src/transaction/mod.rs#L230 + let Some(signature)= TransactionSignature::new( + 38, + array_bytes::hex_n_into_unchecked::<_, _, 32>( + "be67e0a07db67da8d446f76add590e54b6e92cb6b8f9835aeb67540579a27717", + ), + array_bytes::hex_n_into_unchecked::<_, _, 32>( + "2d690516512020171c1ec870f6ff45398cc8609250326be89915fb538e7bd718", + ), + ) else { + log::error!("[pallet::staking] Invalid mock signature for the staking notify transaction."); + return; + }; + + // KTONStakingRewards + let staking_reward = array_bytes::hex_n_into_unchecked::<_, H160, 20>( + "0x000000000419683a1a03AbC21FC9da25fd2B4dD7", + ); + // RewardsDistribution Contract + let reward_distr = array_bytes::hex_n_into_unchecked::<_, H160, 20>( + "0x000000000Ae5DB7BDAf8D071e680452e33d91Dd5", + ); + + let notify_transaction = LegacyTransaction { + nonce: U256::zero(), // Will be reset in the message transact call + gas_price: U256::zero(), // Will be reset in the message transact call + gas_limit: U256::from(10_000_000), /* It should be big enough for the evm + * transaction, otherwise it will out of gas. */ + action: TransactionAction::Call(reward_distr.into()), + value: U256::zero(), + // The selector: distributeRewards(address ktonStakingRewards, uint256 reward) + // https://github.com/darwinia-network/kton-staker/blob/175f0ec131d4aef3bf64cfb2fce1d262e7ce9140/src/RewardsDistribution.sol#L11 + input: ethabi::encode(&[ + Token::Address(staking_reward.into()), + Token::Uint(U256::one()), // TODO + ]), + signature, + }; + + let sender = ::KtonStakerAddress::get(); + if let Err(e) = darwinia_message_transact::Pallet::::message_transact( + LcmpEthOrigin::MessageTransact(sender.into()).into(), + Box::new(Transaction::Legacy(notify_transaction)), + ) { + log::error!("[pallet::staking] failed to notify KTON staker contract due to {:?}", e); + } } } diff --git a/pallet/staking/src/tests.rs b/pallet/staking/src/tests.rs index 3bf72c593..74e8fe0f0 100644 --- a/pallet/staking/src/tests.rs +++ b/pallet/staking/src/tests.rs @@ -18,6 +18,8 @@ // core use core::time::Duration; +// crates.io +use ethereum::TransactionSignature; // darwinia use crate::{mock::*, MigrationCurve, *}; use darwinia_deposit::Error as DepositError; @@ -893,3 +895,17 @@ fn migration_curves_should_work() { ); }); } + +#[test] +fn test_notify_mocked_signature_alway_valid() { + assert!(TransactionSignature::new( + 38, + array_bytes::hex_n_into_unchecked::<_, _, 32>( + "be67e0a07db67da8d446f76add590e54b6e92cb6b8f9835aeb67540579a27717", + ), + array_bytes::hex_n_into_unchecked::<_, _, 32>( + "2d690516512020171c1ec870f6ff45398cc8609250326be89915fb538e7bd718", + ), + ) + .is_some()); +} From bd9e10280fb1be0b0b8a18d3b7f5235f4be460fc Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Thu, 22 Feb 2024 18:01:51 +0800 Subject: [PATCH 09/18] Code optimization Signed-off-by: Xavier Lau --- Cargo.lock | 1 - pallet/staking/Cargo.toml | 13 ++++---- pallet/staking/src/lib.rs | 65 ++++++++++++++++++++----------------- pallet/staking/src/tests.rs | 15 ++------- 4 files changed, 44 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29dca9c93..e101655fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3292,7 +3292,6 @@ dependencies = [ name = "darwinia-staking" version = "6.6.0" dependencies = [ - "array-bytes", "darwinia-deposit", "darwinia-message-transact", "darwinia-staking-traits", diff --git a/pallet/staking/Cargo.toml b/pallet/staking/Cargo.toml index 57262c994..06937ca9f 100644 --- a/pallet/staking/Cargo.toml +++ b/pallet/staking/Cargo.toml @@ -8,12 +8,11 @@ version.workspace = true [dependencies] # crates.io -array-bytes = { workspace = true } -ethereum = { workspace = true } codec = { workspace = true, package = "parity-scale-codec" } +ethabi = { version = "18.0", default-features = false } +ethereum = { workspace = true } log = { workspace = true } scale-info = { workspace = true } -ethabi = { version = "18.0", default-features = false } # darwinia darwinia-message-transact = { workspace = true } @@ -27,9 +26,9 @@ frame-support = { workspace = true } frame-system = { workspace = true } pallet-authorship = { workspace = true } pallet-session = { workspace = true } +sp-core = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } -sp-core = { workspace = true } # substrate optional frame-benchmarking = { workspace = true, optional = true } @@ -55,8 +54,8 @@ default = ["std"] std = [ # crates.io "codec/std", - "log/std", "ethabi/std", + "log/std", "scale-info/std", # darwinia @@ -71,9 +70,9 @@ std = [ "pallet-authorship/std", "pallet-balances/std", "pallet-session/std", + "sp-core/std", "sp-runtime/std", "sp-std/std", - "sp-core/std", # substrate optional "frame-benchmarking?/std", ] @@ -93,6 +92,8 @@ runtime-benchmarks = [ ] try-runtime = [ + # darwinia + "darwinia-message-transact/try-runtime", # substrate "frame-support/try-runtime", "frame-system/try-runtime", diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index 252074237..38dc94604 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -63,7 +63,7 @@ use frame_support::{ pallet_prelude::*, traits::Currency, DefaultNoBound, EqNoBound, PalletId, PartialEqNoBound, }; use frame_system::{pallet_prelude::*, RawOrigin}; -use sp_core::{H160, U256}; +use sp_core::{H160, H256, U256}; use sp_runtime::{ traits::{AccountIdConversion, Convert, One, Zero}, Perbill, Perquintill, @@ -949,7 +949,7 @@ pub mod pallet { reward(staking_pot, actual_reward_v1); reward(T::KtonStakerAddress::get(), reward_to_v2); - T::KtonStakerNotifier::notify(); + T::KtonStakerNotifier::notify(reward_to_v2); } /// Pay the reward to the collator and its nominators. @@ -1278,63 +1278,68 @@ pub fn migration_curve_kton_reward(x: Perquintill) -> Perquintill { /// KTON staker contact notification interface. pub trait KtonStakerNotification { /// Notify the KTON staker contract. - fn notify() {} + fn notify(_: Balance) {} } impl KtonStakerNotification for () {} /// KTON staker contact notifier. pub struct KtonStakerNotifier(PhantomData); impl KtonStakerNotification for KtonStakerNotifier where - T: darwinia_message_transact::Config + Config, + T: Config + darwinia_message_transact::Config, T::RuntimeOrigin: Into> + From, ::AccountId: Into, { - fn notify() { - // Should be a valid mock signature, copied from https://github.com/rust-ethereum/ethereum/blob/master/src/transaction/mod.rs#L230 - let Some(signature)= TransactionSignature::new( - 38, - array_bytes::hex_n_into_unchecked::<_, _, 32>( - "be67e0a07db67da8d446f76add590e54b6e92cb6b8f9835aeb67540579a27717", - ), - array_bytes::hex_n_into_unchecked::<_, _, 32>( - "2d690516512020171c1ec870f6ff45398cc8609250326be89915fb538e7bd718", - ), - ) else { + fn notify(amount: Balance) { + let Some(signature)= mock_sig() else { log::error!("[pallet::staking] Invalid mock signature for the staking notify transaction."); + return; }; - // KTONStakingRewards - let staking_reward = array_bytes::hex_n_into_unchecked::<_, H160, 20>( - "0x000000000419683a1a03AbC21FC9da25fd2B4dD7", - ); + // 0x000000000419683a1a03AbC21FC9da25fd2B4dD7 + let staking_reward = + H160([0, 0, 0, 0, 4, 25, 104, 58, 26, 3, 171, 194, 31, 201, 218, 37, 253, 43, 77, 215]); // RewardsDistribution Contract - let reward_distr = array_bytes::hex_n_into_unchecked::<_, H160, 20>( - "0x000000000Ae5DB7BDAf8D071e680452e33d91Dd5", - ); - + // 0x000000000Ae5DB7BDAf8D071e680452e33d91Dd5 + let reward_distr = H160([ + 0, 0, 0, 0, 10, 229, 219, 123, 218, 248, 208, 113, 230, 128, 69, 46, 51, 217, 29, 213, + ]); let notify_transaction = LegacyTransaction { nonce: U256::zero(), // Will be reset in the message transact call gas_price: U256::zero(), // Will be reset in the message transact call gas_limit: U256::from(10_000_000), /* It should be big enough for the evm * transaction, otherwise it will out of gas. */ - action: TransactionAction::Call(reward_distr.into()), + action: TransactionAction::Call(reward_distr), value: U256::zero(), // The selector: distributeRewards(address ktonStakingRewards, uint256 reward) // https://github.com/darwinia-network/kton-staker/blob/175f0ec131d4aef3bf64cfb2fce1d262e7ce9140/src/RewardsDistribution.sol#L11 - input: ethabi::encode(&[ - Token::Address(staking_reward.into()), - Token::Uint(U256::one()), // TODO - ]), + input: ethabi::encode(&[Token::Address(staking_reward), Token::Uint(amount.into())]), signature, }; - let sender = ::KtonStakerAddress::get(); + if let Err(e) = darwinia_message_transact::Pallet::::message_transact( LcmpEthOrigin::MessageTransact(sender.into()).into(), Box::new(Transaction::Legacy(notify_transaction)), ) { - log::error!("[pallet::staking] failed to notify KTON staker contract due to {:?}", e); + log::error!("[pallet::staking] failed to notify KTON staker contract due to {e:?}"); } } } +/// Mock a valid signature, copied from: +/// https://github.com/rust-ethereum/ethereum/blob/master/src/transaction/mod.rs#L230 +pub fn mock_sig() -> Option { + TransactionSignature::new( + 38, + // be67e0a07db67da8d446f76add590e54b6e92cb6b8f9835aeb67540579a27717 + H256([ + 190, 103, 224, 160, 125, 182, 125, 168, 212, 70, 247, 106, 221, 89, 14, 84, 182, 233, + 44, 182, 184, 249, 131, 90, 235, 103, 84, 5, 121, 162, 119, 23, + ]), + // 2d690516512020171c1ec870f6ff45398cc8609250326be89915fb538e7bd718 + H256([ + 45, 105, 5, 22, 81, 32, 32, 23, 28, 30, 200, 112, 246, 255, 69, 57, 140, 200, 96, 146, + 80, 50, 107, 232, 153, 21, 251, 83, 142, 123, 215, 24, + ]), + ) +} diff --git a/pallet/staking/src/tests.rs b/pallet/staking/src/tests.rs index 74e8fe0f0..ca0e5c610 100644 --- a/pallet/staking/src/tests.rs +++ b/pallet/staking/src/tests.rs @@ -18,8 +18,6 @@ // core use core::time::Duration; -// crates.io -use ethereum::TransactionSignature; // darwinia use crate::{mock::*, MigrationCurve, *}; use darwinia_deposit::Error as DepositError; @@ -897,15 +895,6 @@ fn migration_curves_should_work() { } #[test] -fn test_notify_mocked_signature_alway_valid() { - assert!(TransactionSignature::new( - 38, - array_bytes::hex_n_into_unchecked::<_, _, 32>( - "be67e0a07db67da8d446f76add590e54b6e92cb6b8f9835aeb67540579a27717", - ), - array_bytes::hex_n_into_unchecked::<_, _, 32>( - "2d690516512020171c1ec870f6ff45398cc8609250326be89915fb538e7bd718", - ), - ) - .is_some()); +fn mock_sig_should_work() { + assert!(mock_sig().is_some()); } From 6c9653af7dbb549b653df66665fd39c823c06b85 Mon Sep 17 00:00:00 2001 From: bear Date: Thu, 22 Feb 2024 18:14:40 +0800 Subject: [PATCH 10/18] Fix the call input --- pallet/staking/src/lib.rs | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index 38dc94604..514822b00 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -51,7 +51,7 @@ pub use darwinia_staking_traits::*; use core::mem; // crates.io use codec::FullCodec; -use ethabi::Token; +use ethabi::{Function, Param, ParamType, StateMutability, Token}; use ethereum::{ LegacyTransaction, TransactionAction, TransactionSignature, TransactionV2 as Transaction, }; @@ -1304,6 +1304,31 @@ where let reward_distr = H160([ 0, 0, 0, 0, 10, 229, 219, 123, 218, 248, 208, 113, 230, 128, 69, 46, 51, 217, 29, 213, ]); + // https://github.com/darwinia-network/kton-staker/blob/175f0ec131d4aef3bf64cfb2fce1d262e7ce9140/src/RewardsDistribution.sol#L11 + #[allow(deprecated)] + let function = Function { + name: "distributeRewards".to_string(), + inputs: vec![ + Param { + name: "ktonStakingRewards".to_string(), + kind: ParamType::Address, + internal_type: None, + }, + Param { + name: "reward".to_string(), + kind: ParamType::Uint(256), + internal_type: None, + }, + ], + outputs: vec![Param { + name: "success or not".to_string(), + kind: ParamType::Bool, + internal_type: None, + }], + constant: None, + state_mutability: StateMutability::Payable, + }; + let notify_transaction = LegacyTransaction { nonce: U256::zero(), // Will be reset in the message transact call gas_price: U256::zero(), // Will be reset in the message transact call @@ -1311,9 +1336,9 @@ where * transaction, otherwise it will out of gas. */ action: TransactionAction::Call(reward_distr), value: U256::zero(), - // The selector: distributeRewards(address ktonStakingRewards, uint256 reward) - // https://github.com/darwinia-network/kton-staker/blob/175f0ec131d4aef3bf64cfb2fce1d262e7ce9140/src/RewardsDistribution.sol#L11 - input: ethabi::encode(&[Token::Address(staking_reward), Token::Uint(amount.into())]), + input: function + .encode_input(&[Token::Address(staking_reward.into()), Token::Uint(amount.into())]) + .unwrap_or_default(), signature, }; let sender = ::KtonStakerAddress::get(); From e27afbe5edaa5dd6dbbe0daa71f6d1b0c9cfca12 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Fri, 23 Feb 2024 11:29:23 +0800 Subject: [PATCH 11/18] Fix --- pallet/staking/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pallet/staking/Cargo.toml b/pallet/staking/Cargo.toml index 06937ca9f..3033fc614 100644 --- a/pallet/staking/Cargo.toml +++ b/pallet/staking/Cargo.toml @@ -55,6 +55,7 @@ std = [ # crates.io "codec/std", "ethabi/std", + "ethereum/std", "log/std", "scale-info/std", From bf36e39d820021a32e9b372656a146d729c7e925 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Fri, 23 Feb 2024 12:57:43 +0800 Subject: [PATCH 12/18] Fix compile --- pallet/staking/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index 514822b00..a62a4f093 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -1307,21 +1307,21 @@ where // https://github.com/darwinia-network/kton-staker/blob/175f0ec131d4aef3bf64cfb2fce1d262e7ce9140/src/RewardsDistribution.sol#L11 #[allow(deprecated)] let function = Function { - name: "distributeRewards".to_string(), + name: "distributeRewards".into(), inputs: vec![ Param { - name: "ktonStakingRewards".to_string(), + name: "ktonStakingRewards".into(), kind: ParamType::Address, internal_type: None, }, Param { - name: "reward".to_string(), + name: "reward".into(), kind: ParamType::Uint(256), internal_type: None, }, ], outputs: vec![Param { - name: "success or not".to_string(), + name: "success or not".into(), kind: ParamType::Bool, internal_type: None, }], From 5888ebdfddb4d728273ec353b8732b2070551665 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Fri, 23 Feb 2024 12:59:03 +0800 Subject: [PATCH 13/18] Fix runtime benchmarks --- pallet/staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index a62a4f093..9218342fe 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -487,7 +487,7 @@ pub mod pallet { } if kton_amount != 0 { Self::unstake_token::>(&mut l.staked_kton, None, kton_amount)?; - T::Kton::unstake(&who, kton_amount)?; + ::Kton::unstake(&who, kton_amount)?; } for d in deposits { From 44ab1081add4ec65706dd7915383d21f15dc589c Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Fri, 23 Feb 2024 13:06:02 +0800 Subject: [PATCH 14/18] Rename --- pallet/account-migration/src/mock.rs | 2 +- pallet/staking/src/lib.rs | 10 +++++----- pallet/staking/src/mock.rs | 2 +- precompile/staking/src/mock.rs | 2 +- runtime/crab/src/pallets/staking.rs | 2 +- runtime/darwinia/src/pallets/staking.rs | 2 +- runtime/pangolin/src/pallets/staking.rs | 2 +- runtime/pangoro/src/pallets/staking.rs | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pallet/account-migration/src/mock.rs b/pallet/account-migration/src/mock.rs index 695de5a91..1cb64bdea 100644 --- a/pallet/account-migration/src/mock.rs +++ b/pallet/account-migration/src/mock.rs @@ -164,7 +164,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = (); type Kton = Dummy; - type KtonStakerAddress = (); + type KtonRewardDistributionOwner = (); type KtonStakerNotifier = (); type MaxDeposits = (); type MaxUnstakings = (); diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index 9218342fe..f2209793b 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -157,7 +157,7 @@ pub mod pallet { /// The address of KTON staker contract. #[pallet::constant] - type KtonStakerAddress: Get; + type KtonRewardDistributionOwner: Get; } #[allow(missing_docs)] @@ -947,7 +947,7 @@ pub mod pallet { }; reward(staking_pot, actual_reward_v1); - reward(T::KtonStakerAddress::get(), reward_to_v2); + reward(T::KtonRewardDistributionOwner::get(), reward_to_v2); T::KtonStakerNotifier::notify(reward_to_v2); } @@ -1240,8 +1240,8 @@ where /// ``` /// b"sc/ktstk" /// ``` -pub struct KtonStakerAddress; -impl Get for KtonStakerAddress +pub struct KtonRewardDistributionOwner; +impl Get for KtonRewardDistributionOwner where T: From<[u8; 20]>, { @@ -1341,7 +1341,7 @@ where .unwrap_or_default(), signature, }; - let sender = ::KtonStakerAddress::get(); + let sender = ::KtonRewardDistributionOwner::get(); if let Err(e) = darwinia_message_transact::Pallet::::message_transact( LcmpEthOrigin::MessageTransact(sender.into()).into(), diff --git a/pallet/staking/src/mock.rs b/pallet/staking/src/mock.rs index a00e3adda..820281421 100644 --- a/pallet/staking/src/mock.rs +++ b/pallet/staking/src/mock.rs @@ -341,7 +341,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = StatedOnSessionEnd; type Kton = KtonStaking; - type KtonStakerAddress = (); + type KtonRewardDistributionOwner = (); type KtonStakerNotifier = (); type MaxDeposits = ::MaxDeposits; type MaxUnstakings = frame_support::traits::ConstU32<16>; diff --git a/precompile/staking/src/mock.rs b/precompile/staking/src/mock.rs index 51f2ece5e..3fc323fc8 100644 --- a/precompile/staking/src/mock.rs +++ b/precompile/staking/src/mock.rs @@ -236,7 +236,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = (); type Kton = KtonStaking; - type KtonStakerAddress = (); + type KtonRewardDistributionOwner = (); type KtonStakerNotifier = (); type MaxDeposits = ::MaxDeposits; type MaxUnstakings = frame_support::traits::ConstU32<16>; diff --git a/runtime/crab/src/pallets/staking.rs b/runtime/crab/src/pallets/staking.rs index 55d394423..2d167f30a 100644 --- a/runtime/crab/src/pallets/staking.rs +++ b/runtime/crab/src/pallets/staking.rs @@ -105,7 +105,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = OnCrabSessionEnd; type Kton = KtonStaking; - type KtonStakerAddress = darwinia_staking::KtonStakerAddress; + type KtonRewardDistributionOwner = darwinia_staking::KtonRewardDistributionOwner; type KtonStakerNotifier = darwinia_staking::KtonStakerNotifier; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = ConstU32<16>; diff --git a/runtime/darwinia/src/pallets/staking.rs b/runtime/darwinia/src/pallets/staking.rs index eeb53fc32..a1edd2e05 100644 --- a/runtime/darwinia/src/pallets/staking.rs +++ b/runtime/darwinia/src/pallets/staking.rs @@ -116,7 +116,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = OnDarwiniaSessionEnd; type Kton = KtonStaking; - type KtonStakerAddress = darwinia_staking::KtonStakerAddress; + type KtonRewardDistributionOwner = darwinia_staking::KtonRewardDistributionOwner; type KtonStakerNotifier = darwinia_staking::KtonStakerNotifier; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = ConstU32<16>; diff --git a/runtime/pangolin/src/pallets/staking.rs b/runtime/pangolin/src/pallets/staking.rs index 76eebfbb0..fa1127f5a 100644 --- a/runtime/pangolin/src/pallets/staking.rs +++ b/runtime/pangolin/src/pallets/staking.rs @@ -99,7 +99,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = OnPangolinSessionEnd; type Kton = KtonStaking; - type KtonStakerAddress = darwinia_staking::KtonStakerAddress; + type KtonRewardDistributionOwner = darwinia_staking::KtonRewardDistributionOwner; type KtonStakerNotifier = darwinia_staking::KtonStakerNotifier; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = ConstU32<16>; diff --git a/runtime/pangoro/src/pallets/staking.rs b/runtime/pangoro/src/pallets/staking.rs index ba184b6d0..ee75c8fbe 100644 --- a/runtime/pangoro/src/pallets/staking.rs +++ b/runtime/pangoro/src/pallets/staking.rs @@ -112,7 +112,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = OnPangoroSessionEnd; type Kton = KtonStaking; - type KtonStakerAddress = darwinia_staking::KtonStakerAddress; + type KtonRewardDistributionOwner = darwinia_staking::KtonRewardDistributionOwner; type KtonStakerNotifier = darwinia_staking::KtonStakerNotifier; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = ConstU32<16>; From 99184a30efd7dd022ff47e9ff39beb74f6b7c736 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Fri, 23 Feb 2024 13:51:30 +0800 Subject: [PATCH 15/18] Format --- pallet/staking/src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index f2209793b..464f0fc29 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -1314,11 +1314,7 @@ where kind: ParamType::Address, internal_type: None, }, - Param { - name: "reward".into(), - kind: ParamType::Uint(256), - internal_type: None, - }, + Param { name: "reward".into(), kind: ParamType::Uint(256), internal_type: None }, ], outputs: vec![Param { name: "success or not".into(), From c6dc06adee972e17aab92513e59ac2d9b56fdde8 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Fri, 23 Feb 2024 13:58:03 +0800 Subject: [PATCH 16/18] Revert curve algorithm --- pallet/staking/src/lib.rs | 8 +------- pallet/staking/src/tests.rs | 23 ++++++++++------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index 464f0fc29..46305da2c 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -921,7 +921,7 @@ pub mod pallet { let reward_to_ring = amount / 2; let reward_to_kton = amount - reward_to_ring; #[cfg(not(any(test, feature = "runtime-benchmarks")))] - let ratio = migration_curve_kton_reward(T::MigrationCurve::get()); + let ratio = T::MigrationCurve::get(); #[cfg(any(test, feature = "runtime-benchmarks"))] let ratio = Perquintill::one(); let reward_to_kton_v1 = ratio * reward_to_kton; @@ -1268,12 +1268,6 @@ where Perquintill::one() - Perquintill::from_rational(x, month_in_blocks) } } -/// The KTON reward curve during migrating to staking v2. -pub fn migration_curve_kton_reward(x: Perquintill) -> Perquintill { - let x = x.deconstruct(); - - Perquintill::from_rational(x, x + Perquintill::one().deconstruct()) -} /// KTON staker contact notification interface. pub trait KtonStakerNotification { diff --git a/pallet/staking/src/tests.rs b/pallet/staking/src/tests.rs index ca0e5c610..fe5ddfb31 100644 --- a/pallet/staking/src/tests.rs +++ b/pallet/staking/src/tests.rs @@ -873,22 +873,19 @@ fn migration_curves_should_work() { .map(|x| { System::set_block_number(10 + x * 24 * 60 * 60 / 12); - let x = >::get(); - let y = migration_curve_kton_reward(x); - - format!("{x:?} -> {y:?}") + format!("{:?}", >::get()) }) .collect::>(), [ - "99.9995370370370371% -> 49.9998842589913402%", - "96.6666666666666667% -> 49.1525423728813559%", - "76.6666666666666667% -> 43.3962264150943396%", - "53.3333333333333334% -> 34.7826086956521739%", - "30% -> 23.0769230769230769%", - "3.3333333333333334% -> 3.2258064516129032%", - "0% -> 0%", - "0% -> 0%", - "0% -> 0%" + "99.9995370370370371%", + "96.6666666666666667%", + "76.6666666666666667%", + "53.3333333333333334%", + "30%", + "3.3333333333333334%", + "0%", + "0%", + "0%" ] ); }); From b8b8611e3c0716e8a57f6971b7a73e2728b62d28 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Fri, 23 Feb 2024 14:03:11 +0800 Subject: [PATCH 17/18] Lower gas limit --- pallet/staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index 46305da2c..40017237b 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -1322,7 +1322,7 @@ where let notify_transaction = LegacyTransaction { nonce: U256::zero(), // Will be reset in the message transact call gas_price: U256::zero(), // Will be reset in the message transact call - gas_limit: U256::from(10_000_000), /* It should be big enough for the evm + gas_limit: U256::from(1_000_000), /* It should be big enough for the evm * transaction, otherwise it will out of gas. */ action: TransactionAction::Call(reward_distr), value: U256::zero(), From f6f954c66f7551d718060573719e1079c8bcc59e Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Fri, 23 Feb 2024 14:10:44 +0800 Subject: [PATCH 18/18] Correct addresses --- pallet/account-migration/src/mock.rs | 2 +- pallet/staking/src/lib.rs | 36 ++++++++++++------------- pallet/staking/src/mock.rs | 2 +- precompile/staking/src/mock.rs | 2 +- runtime/crab/src/pallets/staking.rs | 2 +- runtime/darwinia/src/pallets/staking.rs | 2 +- runtime/pangolin/src/pallets/staking.rs | 2 +- runtime/pangoro/src/pallets/staking.rs | 2 +- 8 files changed, 24 insertions(+), 26 deletions(-) diff --git a/pallet/account-migration/src/mock.rs b/pallet/account-migration/src/mock.rs index 1cb64bdea..b3c715aaf 100644 --- a/pallet/account-migration/src/mock.rs +++ b/pallet/account-migration/src/mock.rs @@ -164,7 +164,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = (); type Kton = Dummy; - type KtonRewardDistributionOwner = (); + type KtonRewardDistributionContract = (); type KtonStakerNotifier = (); type MaxDeposits = (); type MaxUnstakings = (); diff --git a/pallet/staking/src/lib.rs b/pallet/staking/src/lib.rs index 40017237b..b12fb6ac4 100644 --- a/pallet/staking/src/lib.rs +++ b/pallet/staking/src/lib.rs @@ -155,9 +155,9 @@ pub mod pallet { /// The curve of migration. type MigrationCurve: Get; - /// The address of KTON staker contract. + /// The address of KTON reward distribution contract. #[pallet::constant] - type KtonRewardDistributionOwner: Get; + type KtonRewardDistributionContract: Get; } #[allow(missing_docs)] @@ -947,7 +947,7 @@ pub mod pallet { }; reward(staking_pot, actual_reward_v1); - reward(T::KtonRewardDistributionOwner::get(), reward_to_v2); + reward(T::KtonRewardDistributionContract::get(), reward_to_v2); T::KtonStakerNotifier::notify(reward_to_v2); } @@ -1236,17 +1236,16 @@ where PalletId(*b"da/staki").into_account_truncating() } -/// The address of the KTON staker contract. -/// ``` -/// b"sc/ktstk" -/// ``` -pub struct KtonRewardDistributionOwner; -impl Get for KtonRewardDistributionOwner +/// The address of the RewardsDistribution. +/// 0x000000000Ae5DB7BDAf8D071e680452e33d91Dd5. +pub struct KtonRewardDistributionContract; +impl Get for KtonRewardDistributionContract where T: From<[u8; 20]>, { fn get() -> T { - [115, 99, 47, 107, 116, 115, 116, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].into() + [0, 0, 0, 0, 10, 229, 219, 123, 218, 248, 208, 113, 230, 128, 69, 46, 51, 217, 29, 213] + .into() } } @@ -1293,11 +1292,8 @@ where // 0x000000000419683a1a03AbC21FC9da25fd2B4dD7 let staking_reward = H160([0, 0, 0, 0, 4, 25, 104, 58, 26, 3, 171, 194, 31, 201, 218, 37, 253, 43, 77, 215]); - // RewardsDistribution Contract - // 0x000000000Ae5DB7BDAf8D071e680452e33d91Dd5 - let reward_distr = H160([ - 0, 0, 0, 0, 10, 229, 219, 123, 218, 248, 208, 113, 230, 128, 69, 46, 51, 217, 29, 213, - ]); + + let reward_distr = T::KtonRewardDistributionContract::get().into(); // https://github.com/darwinia-network/kton-staker/blob/175f0ec131d4aef3bf64cfb2fce1d262e7ce9140/src/RewardsDistribution.sol#L11 #[allow(deprecated)] let function = Function { @@ -1327,14 +1323,16 @@ where action: TransactionAction::Call(reward_distr), value: U256::zero(), input: function - .encode_input(&[Token::Address(staking_reward.into()), Token::Uint(amount.into())]) + .encode_input(&[Token::Address(staking_reward), Token::Uint(amount.into())]) .unwrap_or_default(), signature, }; - let sender = ::KtonRewardDistributionOwner::get(); + // b"sc/ktstk" + let sender = + H160([115, 99, 47, 107, 116, 115, 116, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - if let Err(e) = darwinia_message_transact::Pallet::::message_transact( - LcmpEthOrigin::MessageTransact(sender.into()).into(), + if let Err(e) = >::message_transact( + LcmpEthOrigin::MessageTransact(sender).into(), Box::new(Transaction::Legacy(notify_transaction)), ) { log::error!("[pallet::staking] failed to notify KTON staker contract due to {e:?}"); diff --git a/pallet/staking/src/mock.rs b/pallet/staking/src/mock.rs index 820281421..4c39af409 100644 --- a/pallet/staking/src/mock.rs +++ b/pallet/staking/src/mock.rs @@ -341,7 +341,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = StatedOnSessionEnd; type Kton = KtonStaking; - type KtonRewardDistributionOwner = (); + type KtonRewardDistributionContract = (); type KtonStakerNotifier = (); type MaxDeposits = ::MaxDeposits; type MaxUnstakings = frame_support::traits::ConstU32<16>; diff --git a/precompile/staking/src/mock.rs b/precompile/staking/src/mock.rs index 3fc323fc8..cb94d8dc6 100644 --- a/precompile/staking/src/mock.rs +++ b/precompile/staking/src/mock.rs @@ -236,7 +236,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = (); type Kton = KtonStaking; - type KtonRewardDistributionOwner = (); + type KtonRewardDistributionContract = (); type KtonStakerNotifier = (); type MaxDeposits = ::MaxDeposits; type MaxUnstakings = frame_support::traits::ConstU32<16>; diff --git a/runtime/crab/src/pallets/staking.rs b/runtime/crab/src/pallets/staking.rs index 2d167f30a..c5855f1e2 100644 --- a/runtime/crab/src/pallets/staking.rs +++ b/runtime/crab/src/pallets/staking.rs @@ -105,7 +105,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = OnCrabSessionEnd; type Kton = KtonStaking; - type KtonRewardDistributionOwner = darwinia_staking::KtonRewardDistributionOwner; + type KtonRewardDistributionContract = darwinia_staking::KtonRewardDistributionContract; type KtonStakerNotifier = darwinia_staking::KtonStakerNotifier; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = ConstU32<16>; diff --git a/runtime/darwinia/src/pallets/staking.rs b/runtime/darwinia/src/pallets/staking.rs index a1edd2e05..fe427555a 100644 --- a/runtime/darwinia/src/pallets/staking.rs +++ b/runtime/darwinia/src/pallets/staking.rs @@ -116,7 +116,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = OnDarwiniaSessionEnd; type Kton = KtonStaking; - type KtonRewardDistributionOwner = darwinia_staking::KtonRewardDistributionOwner; + type KtonRewardDistributionContract = darwinia_staking::KtonRewardDistributionContract; type KtonStakerNotifier = darwinia_staking::KtonStakerNotifier; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = ConstU32<16>; diff --git a/runtime/pangolin/src/pallets/staking.rs b/runtime/pangolin/src/pallets/staking.rs index fa1127f5a..f02b17f77 100644 --- a/runtime/pangolin/src/pallets/staking.rs +++ b/runtime/pangolin/src/pallets/staking.rs @@ -99,7 +99,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = OnPangolinSessionEnd; type Kton = KtonStaking; - type KtonRewardDistributionOwner = darwinia_staking::KtonRewardDistributionOwner; + type KtonRewardDistributionContract = darwinia_staking::KtonRewardDistributionContract; type KtonStakerNotifier = darwinia_staking::KtonStakerNotifier; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = ConstU32<16>; diff --git a/runtime/pangoro/src/pallets/staking.rs b/runtime/pangoro/src/pallets/staking.rs index ee75c8fbe..27f26cab3 100644 --- a/runtime/pangoro/src/pallets/staking.rs +++ b/runtime/pangoro/src/pallets/staking.rs @@ -112,7 +112,7 @@ impl darwinia_staking::Config for Runtime { type Deposit = Deposit; type IssuingManager = OnPangoroSessionEnd; type Kton = KtonStaking; - type KtonRewardDistributionOwner = darwinia_staking::KtonRewardDistributionOwner; + type KtonRewardDistributionContract = darwinia_staking::KtonRewardDistributionContract; type KtonStakerNotifier = darwinia_staking::KtonStakerNotifier; type MaxDeposits = ::MaxDeposits; type MaxUnstakings = ConstU32<16>;