From caed4c9a2597b8a86c6da5f97da8e39c238c0310 Mon Sep 17 00:00:00 2001 From: toints Date: Fri, 29 Mar 2024 13:34:31 +0800 Subject: [PATCH 1/2] perf(*): update liquidation pallet to polkadot-v1.7.0 --- Cargo.lock | 5 ++ pallets/liquidation/Cargo.toml | 10 +++ pallets/liquidation/src/lib.rs | 101 ++++++++++++++++++++++-- pallets/liquidation/src/mock.rs | 133 ++++++++++++++++++++++++++++++-- runtime/src/lib.rs | 3 + 5 files changed, 239 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2893b34..2214ef8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7616,6 +7616,7 @@ dependencies = [ name = "pallet-liquidation" version = "0.1.0" dependencies = [ + "cumulus-pallet-xcmp-queue", "frame-benchmarking", "frame-support", "frame-system", @@ -7627,6 +7628,7 @@ dependencies = [ "pallet-pot", "pallet-transaction-payment", "pallet-utility", + "pallet-xcm", "parity-scale-codec", "scale-info", "smallvec", @@ -7635,6 +7637,9 @@ dependencies = [ "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.7.0)", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", ] [[package]] diff --git a/pallets/liquidation/Cargo.toml b/pallets/liquidation/Cargo.toml index 6040dbf..0ec4b1a 100644 --- a/pallets/liquidation/Cargo.toml +++ b/pallets/liquidation/Cargo.toml @@ -35,6 +35,11 @@ frame-support = { workspace = true, default-features = false } frame-system = { workspace = true, default-features = false } frame-benchmarking = { workspace = true, default-features = false, optional = true} pallet-utility = { workspace = true, default-features = false} +xcm = { workspace = true, default-features = false} +xcm-builder = { workspace = true, default-features = false} +cumulus-pallet-xcmp-queue = { workspace = true, default-features = false} +xcm-executor = { workspace = true, default-features = false} +pallet-xcm = {workspace = true, default-features = false} [features] default = ['std'] @@ -58,6 +63,11 @@ std = [ "mp-system/std", "pallet-utility/std", "frame-benchmarking/std", + "pallet-xcm/std", + "xcm/std", + "xcm-builder/std", + "cumulus-pallet-xcmp-queue/std", + "xcm-executor/std", ] try-runtime = [ "frame-support/try-runtime", diff --git a/pallets/liquidation/src/lib.rs b/pallets/liquidation/src/lib.rs index a22b8a8..b6cdc19 100644 --- a/pallets/liquidation/src/lib.rs +++ b/pallets/liquidation/src/lib.rs @@ -7,25 +7,35 @@ mod mock; mod tests; use frame_support::{ + dispatch::DispatchResult, storage::types::StorageMap, traits::{Currency, ExistenceRequirement, Get}, weights::WeightToFeePolynomial, Twox64Concat, }; -use frame_system::pallet_prelude::BlockNumberFor; +use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; use mp_system::BASE_ACCOUNT; pub use pallet::*; use sp_runtime::{ traits::{StaticLookup, Zero}, AccountId32, Perbill, Saturating, }; -use sp_std::{prelude::*, vec}; +use sp_std::{prelude::*, sync::Arc, vec}; + +use xcm::{ + opaque::v4::Junctions::X1, + prelude::*, + v4::{Asset, AssetId, Junction, Location, NetworkId}, + VersionedAssets, VersionedLocation, +}; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; pub type Balance = u128; +pub const PARACHAIN_TO_RELAYCHAIN_UNIT: u128 = 1_0000_0000; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -54,6 +64,13 @@ pub mod pallet { type Currency: frame_support::traits::Currency + frame_support::traits::ReservableCurrency; + /// The XCM sender + type XcmSender: SendXcm; + + //Treasury account on the Relay Chain + //#[pallet::constant] + //type RelayChainTreasuryAccountId: Get; + ///Handles converting weight to fee value type WeightToFee: WeightToFeePolynomial; @@ -76,6 +93,10 @@ pub mod pallet { #[pallet::constant] type ExistentialDeposit: Get; + ///minimum liquidation threshold + #[pallet::constant] + type MinLiquidationThreshold: Get; + /// system accountId #[pallet::constant] type SystemAccountName: Get<&'static str>; @@ -154,14 +175,18 @@ pub mod pallet { ///failed to process liquidation ProcessLiquidationError, + + ///xcm error + XcmError, } #[pallet::hooks] impl Hooks> for Pallet where - T::AccountId: From, + T::AccountId: From + Into, ::RuntimeCall: From>, ::Balance: From>, + T: pallet_xcm::Config, { fn on_finalize(n: BlockNumberFor) { let base_account = ::from(BASE_ACCOUNT); @@ -226,7 +251,15 @@ pub mod pallet { *income = income.saturating_add(current_block_fee_u128) }); - if count % T::ProfitDistributionCycle::get() == Zero::zero() { + let min_liquidation_threshold: Balance = + ::MinLiquidationThreshold::get() + .try_into() + .unwrap_or_else(|_| 0); + let profit = TotalIncome::::get().saturating_sub(TotalCost::::get()); + + if profit >= min_liquidation_threshold + && count % T::ProfitDistributionCycle::get() == Zero::zero() + { DistributionBlockCount::::put(BlockNumberFor::::zero()); match Self::distribute_profit() { Ok(_) => { @@ -252,9 +285,11 @@ pub mod pallet { impl Pallet where - T::AccountId: From, + T::AccountId: From + Into, ::RuntimeCall: From>, ::Balance: From>, + T::XcmSender: SendXcm, + T: pallet_xcm::Config, { fn execute_batch_transfers( transfers: Vec<(T::AccountId, BalanceOf)>, @@ -284,7 +319,7 @@ pub mod pallet { calls.push(utility_call); } - pallet_utility::Pallet::::batch( + pallet_utility::Pallet::::batch_all( frame_system::RawOrigin::Signed(system_account).into(), calls, ) @@ -351,17 +386,27 @@ pub mod pallet { let treasury_ratio = T::TreasuryRatio::get(); let operation_ratio = T::OperationRatio::get(); - let treasury_amount = treasury_ratio * total_profit; + let treasury_amount = treasury_ratio * total_profit / PARACHAIN_TO_RELAYCHAIN_UNIT; let operation_amount = operation_ratio * total_profit; let system_amount = system_ratio * total_profit; let total_collators_profit = total_profit.saturating_sub(treasury_amount + operation_amount + system_amount); - let mut transfers = Vec::new(); + let origin: OriginFor = + frame_system::RawOrigin::Signed(treasury_account.clone()).into(); + let _send_treasury_profit = Self::send_assets_to_relaychain_treasury( + origin, + treasury_account.into(), + treasury_amount, + )?; + + let mut transfers = Vec::new(); + /* let treasury_account_profit = treasury_amount.try_into().unwrap_or_else(|_| Zero::zero()); transfers.push((treasury_account, treasury_account_profit)); + */ let operation_account_profit = operation_amount.try_into().unwrap_or_else(|_| Zero::zero()); @@ -392,5 +437,45 @@ pub mod pallet { } Self::execute_batch_transfers(transfers) } + + fn send_assets_to_relaychain_treasury( + origin: OriginFor, + recipient: AccountId32, + amount: u128, + ) -> DispatchResult { + let recipient_account_id = recipient.into(); + + let junction = Junction::AccountId32 { + id: recipient_account_id, + network: Some(NetworkId::Rococo), + }; + let arc_junctions = Arc::new([junction]); + + let beneficiary = Location::new(0, X1(arc_junctions)); + + let asset = + Asset { id: AssetId(Location::new(1, Here)), fun: Fungibility::Fungible(amount) }; + + let assets = Assets::from(vec![asset]); + let versioned_assets = VersionedAssets::from(assets); + + match pallet_xcm::Pallet::::reserve_transfer_assets( + origin, + Box::new(VersionedLocation::from(Location::parent())), + Box::new(VersionedLocation::from(beneficiary)), + Box::new(versioned_assets), + 0, + ) { + Ok(_) => { + frame_support::runtime_print!("reserve_transfer_assets executed successfully."); + }, + Err(e) => { + log::error!("Error occurred while executing reserve_transfer_assets: {:?}", e); + Self::deposit_event(Event::Error(Error::::XcmError.into())); + return Err(Error::::XcmError.into()); + }, + } + Ok(()) + } } } diff --git a/pallets/liquidation/src/mock.rs b/pallets/liquidation/src/mock.rs index bc8404d..170d6f6 100644 --- a/pallets/liquidation/src/mock.rs +++ b/pallets/liquidation/src/mock.rs @@ -1,14 +1,17 @@ pub(crate) use crate as pallet_liquidation; pub(crate) use crate::Event as LiquidationEvent; +use codec::Encode; +use frame_support::traits::{Everything, Nothing}; use frame_support::{ - derive_impl, parameter_types, + parameter_types, traits::{ConstU32, ConstU64}, weights::{ - constants::ExtrinsicBaseWeight, WeightToFeeCoefficient, WeightToFeeCoefficients, + constants::ExtrinsicBaseWeight, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }, }; use frame_system as system; +use frame_system::EnsureRoot; use smallvec::smallvec; use sp_core::H256; use sp_runtime::{ @@ -19,7 +22,15 @@ use sp_runtime::{ use frame_system::pallet_prelude::BlockNumberFor; use pallet_order::OrderGasCost; use sp_consensus_aura::sr25519::AuthorityId as AuraId; -use sp_std::collections::btree_map::BTreeMap; +use sp_std::{cell::RefCell, collections::btree_map::BTreeMap}; +use xcm::latest::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}; +use xcm::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, FixedRateOfFungible, FixedWeightBounds, IsConcrete, + SignedToAccountId32, TakeWeightCredit, +}; +use xcm_executor::XcmExecutor; type Balance = u128; type BlockNumber = u32; @@ -37,6 +48,7 @@ frame_support::construct_runtime!( Pot: pallet_pot::{Pallet, Call, Storage, Event}, Utility: pallet_utility::{Pallet, Call, Storage, Event}, Liquidation: pallet_liquidation::{Pallet, Storage, Event}, + XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config}, } ); @@ -62,12 +74,12 @@ parameter_types! { pub const OperationRatio: Perbill = Perbill::from_percent(25); // 25% for maintenance pub const ProfitDistributionCycle: BlockNumber = 10; pub const ExistDeposit: Balance = EXISTENTIAL_DEPOSIT; + pub const MinLiquidationThreshold: Balance = MILLIUNIT * 20; pub const SystemAccountName: &'static str = "system"; pub const TreasuryAccountName: &'static str = "treasury"; pub const OperationAccountName: &'static str = "maintenance"; } -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig as frame_system::DefaultConfig)] impl system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -92,6 +104,7 @@ impl system::Config for Test { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type RuntimeOrigin = RuntimeOrigin; + type RuntimeTask = (); } parameter_types! { @@ -110,8 +123,8 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type RuntimeHoldReason = (); type FreezeIdentifier = (); - type RuntimeFreezeReason = (); type MaxFreezes = (); + type RuntimeFreezeReason = (); } impl pallet_utility::Config for Test { @@ -139,6 +152,8 @@ impl pallet_order::Config for Test { } use pallet_pot::PotNameBtreemap; +use pallet_xcm::TestWeightInfo; + pub type AccountId = AccountId32; parameter_types! { pub const PotNames: [&'static str;3] = ["system", "treasury", "maintenance"]; @@ -154,15 +169,123 @@ impl pallet_pot::Config for Test { type Pots = Pots; } +thread_local! { + pub static SENT_XCM: RefCell)>> = RefCell::new(Vec::new()); +} + +pub(crate) fn fake_message_hash(message: &Xcm) -> XcmHash { + message.using_encoded(sp_io::hashing::blake2_256) +} + +pub struct TestSendXcm; +impl SendXcm for TestSendXcm { + type Ticket = (Location, Xcm<()>); + fn validate( + dest: &mut Option, + msg: &mut Option>, + ) -> SendResult<(Location, Xcm<()>)> { + let pair = (dest.take().unwrap(), msg.take().unwrap()); + Ok((pair, Assets::new())) + } + fn deliver(pair: (Location, Xcm<()>)) -> Result { + let hash = fake_message_hash(&pair.1); + SENT_XCM.with(|q| q.borrow_mut().push(pair)); + Ok(hash) + } +} + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; + pub XcmFeesTargetAccount: AccountId = AccountId::new([167u8; 32]); + pub UniversalLocation: InteriorLocation = Here; + pub const AnyNetwork: Option = None; + pub const RelayLocation: Location = Here.into_location(); + pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (AssetId(RelayLocation::get()), 1, 1); +} + +pub struct XcmConfig; +pub type Barrier = ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + AllowKnownQueryResponses, + AllowSubscriptionsFrom, +); + +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = (); + type OriginConverter = (); + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = FixedRateOfFungible; + type ResponseHandler = XcmPallet; + type AssetTrap = XcmPallet; + type AssetLocker = (); + type AssetExchanger = (); + type AssetClaims = XcmPallet; + type SubscriptionService = XcmPallet; + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + //type FeeManager = XcmFeeManagerFromComponents< + // EverythingBut, + // XcmFeeToAccount, + //>; + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = (); +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +impl pallet_xcm::Config for Test { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = (); + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type AdminOrigin = EnsureRoot; + type TrustedLockers = (); + type SovereignAccountOf = AccountId32Aliases<(), AccountId32>; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type MaxLockers = frame_support::traits::ConstU32<8>; + type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = TestWeightInfo; +} + +pub type XcmRouter = TestSendXcm; + impl pallet_liquidation::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; + type XcmSender = XcmRouter; type WeightToFee = WeightToFee; type OrderGasCost = MockOrderGasCostHandler; type SystemRatio = SystemRatio; type TreasuryRatio = TreasuryRatio; type OperationRatio = OperationRatio; type ExistentialDeposit = ExistDeposit; + type MinLiquidationThreshold = MinLiquidationThreshold; type SystemAccountName = SystemAccountName; type TreasuryAccountName = TreasuryAccountName; type OperationAccountName = OperationAccountName; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index e5267ac..9071ea0 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -943,6 +943,7 @@ parameter_types! { pub const OperationRatio: Perbill = Perbill::from_percent(25); // 25% for maintenance pub const ProfitDistributionCycle: BlockNumber = 10; pub const ExistDeposit: Balance = EXISTENTIAL_DEPOSIT; + pub const MinLiquidationThreshold: Balance = MILLIUNIT * 20; pub const SystemAccountName: &'static str = "system"; pub const TreasuryAccountName: &'static str = "treasury"; pub const OperationAccountName: &'static str = "maintenance"; @@ -951,12 +952,14 @@ parameter_types! { impl pallet_liquidation::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; + type XcmSender = xcm_config::XcmRouter; type WeightToFee = WeightToFee; type OrderGasCost = OrderGasCostHandler; type SystemRatio = SystemRatio; type TreasuryRatio = TreasuryRatio; type OperationRatio = OperationRatio; type ExistentialDeposit = ExistDeposit; + type MinLiquidationThreshold = MinLiquidationThreshold; type SystemAccountName = SystemAccountName; type TreasuryAccountName = TreasuryAccountName; type OperationAccountName = OperationAccountName; From 7352585d4fbf5caf4c1b3a7e52e22ed463e1ec5f Mon Sep 17 00:00:00 2001 From: toints Date: Mon, 1 Apr 2024 11:11:59 +0800 Subject: [PATCH 2/2] fix: fixed token precision --- pallets/liquidation/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/liquidation/src/lib.rs b/pallets/liquidation/src/lib.rs index 2272430..2ca4b5a 100644 --- a/pallets/liquidation/src/lib.rs +++ b/pallets/liquidation/src/lib.rs @@ -34,7 +34,7 @@ type BalanceOf = pub type Balance = u128; -pub const PARACHAIN_TO_RELAYCHAIN_UNIT: u128 = 1_0000_0000; +pub const PARACHAIN_TO_RELAYCHAIN_UNIT: u128 = 1_000_000; #[frame_support::pallet] pub mod pallet {