diff --git a/runtime/amplitude/Cargo.toml b/runtime/amplitude/Cargo.toml index cf776d086..c2c96240c 100644 --- a/runtime/amplitude/Cargo.toml +++ b/runtime/amplitude/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.40" } [dependencies] +cfg-if = "1.0.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.17", default-features = false } @@ -104,8 +105,8 @@ orml-xcm-support = { git = "https://github.com/open-web3-stack/open-runtime-modu # KILT parachain-staking = { path = "../../pallets/parachain-staking", default-features = false } -orml-currencies-allowance-extension = { path = "../../pallets/orml-currencies-allowance-extension", default-features = false } - +orml-currencies-allowance-extension = {path = "../../pallets/orml-currencies-allowance-extension", default-features = false} +treasury-buyout-extension = {path = "../../pallets/treasury-buyout-extension", default-features = false} # Pendulum Pallets vesting-manager = { path = "../../pallets/vesting-manager", default-features = false } @@ -237,10 +238,12 @@ std = [ "module-pallet-staking-rpc-runtime-api/std", "module-vault-registry-rpc-runtime-api/std", "spacewalk-primitives/std", - # custom libraries from pendulum - "orml-currencies-allowance-extension/std", - "parachain-staking/std", - "vesting-manager/std", + # custom libraries from pendulum + "orml-currencies-allowance-extension/std", + "treasury-buyout-extension/std", + "parachain-staking/std", + "vesting-manager/std", + ] runtime-benchmarks = [ @@ -266,7 +269,8 @@ runtime-benchmarks = [ "cumulus-pallet-xcmp-queue/runtime-benchmarks", "pallet-collective/runtime-benchmarks", "runtime-common/runtime-benchmarks", - "orml-currencies-allowance-extension/runtime-benchmarks" + "orml-currencies-allowance-extension/runtime-benchmarks", + "treasury-buyout-extension/runtime-benchmarks" ] try-runtime = [ @@ -321,7 +325,8 @@ try-runtime = [ "reward-distribution/try-runtime", "dia-oracle/try-runtime", "orml-currencies-allowance-extension/try-runtime", + "treasury-buyout-extension/try-runtime", "vesting-manager/try-runtime", "bifrost-farming/try-runtime", "zenlink-protocol/try-runtime", -] \ No newline at end of file +] diff --git a/runtime/amplitude/src/lib.rs b/runtime/amplitude/src/lib.rs index 83fbd31d1..eaf209655 100644 --- a/runtime/amplitude/src/lib.rs +++ b/runtime/amplitude/src/lib.rs @@ -29,14 +29,16 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Convert, ConvertInto, + One, Zero, }, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, DispatchError, FixedPointNumber, SaturatedConversion, + ApplyExtrinsicResult, DispatchError, FixedPointNumber, FixedU128, SaturatedConversion, }; const CONTRACTS_DEBUG_OUTPUT: bool = true; -use sp_std::{marker::PhantomData, prelude::*}; +use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; + #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -85,6 +87,7 @@ pub use nomination::Event as NominationEvent; use oracle::{ dia, dia::{DiaOracleAdapter, NativeCurrencyKey, XCMCurrencyConversion}, + OracleKey, }; pub use redeem::{Event as RedeemEvent, RedeemRequest}; pub use replace::{Event as ReplaceEvent, ReplaceRequest}; @@ -135,6 +138,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + treasury_buyout_extension::CheckBuyout, ); /// Unchecked extrinsic type as expected by this runtime. @@ -183,14 +187,30 @@ impl XCMCurrencyConversion for AmplitudeDiaOracleKeyConverter { } } -type DataProviderImpl = DiaOracleAdapter< - DiaOracleModule, - UnsignedFixedPoint, - Moment, - dia::DiaOracleKeyConvertor, - ConvertPrice, - ConvertMoment, ->; +cfg_if::cfg_if! { + if #[cfg(feature = "runtime-benchmarks")] { + use oracle::testing_utils::{ + MockConvertMoment, MockConvertPrice, MockDiaOracle, MockOracleKeyConvertor, + }; + type DataProviderImpl = DiaOracleAdapter< + MockDiaOracle, + UnsignedFixedPoint, + Moment, + MockOracleKeyConvertor, + MockConvertPrice, + MockConvertMoment, + >; + } else { + type DataProviderImpl = DiaOracleAdapter< + DiaOracleModule, + UnsignedFixedPoint, + Moment, + dia::DiaOracleKeyConvertor, + ConvertPrice, + ConvertMoment, + >; + } +} pub struct ConvertPrice; @@ -371,6 +391,7 @@ impl Contains for BaseFilter { RuntimeCall::TokenAllowance(_) | RuntimeCall::AssetRegistry(_) | RuntimeCall::Proxy(_) | + RuntimeCall::TreasuryBuyoutExtension(_) | RuntimeCall::RewardDistribution(_) => true, // All pallets are allowed, but exhaustive match is defensive // in the case of adding new pallets. @@ -1056,6 +1077,7 @@ where frame_system::CheckNonce::::from(index), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), + treasury_buyout_extension::CheckBuyout::::new(), ); let raw_payload = SignedPayload::new(call, extra).ok()?; @@ -1315,6 +1337,82 @@ impl orml_currencies_allowance_extension::Config for Runtime { type MaxAllowedCurrencies = ConstU32<256>; } +pub struct OraclePriceGetter(Oracle); + +impl treasury_buyout_extension::PriceGetter for OraclePriceGetter { + #[cfg(not(feature = "runtime-benchmarks"))] + fn get_price(currency_id: CurrencyId) -> Result + where + FixedNumber: FixedPointNumber + One + Zero + Debug + TryFrom, + { + let key = OracleKey::ExchangeRate(currency_id); + let asset_price = Oracle::get_price(key.clone())?; + + let converted_asset_price = FixedNumber::try_from(asset_price); + + match converted_asset_price { + Ok(price) => Ok(price), + Err(_) => Err(DispatchError::Other("Failed to convert price")), + } + } + + #[cfg(feature = "runtime-benchmarks")] + fn get_price(currency_id: CurrencyId) -> Result + where + FixedNumber: FixedPointNumber + One + Zero + Debug + TryFrom, + { + // Forcefully set chain status to running when benchmarking so that the oracle doesn't fail + Security::set_status(StatusCode::Running); + + let key = OracleKey::ExchangeRate(currency_id); + + // Attempt to get the price once and use the result to decide if feeding a value is necessary + match Oracle::get_price(key.clone()) { + Ok(asset_price) => { + // If the price is successfully retrieved, use it directly + let converted_asset_price = FixedNumber::try_from(asset_price) + .map_err(|_| DispatchError::Other("Failed to convert price"))?; + Ok(converted_asset_price) + }, + Err(_) => { + // Price not found, feed the default value + let rate = FixedU128::checked_from_rational(100, 1).expect("This is a valid ratio"); + // Account used for feeding values + let account = AccountId::from([0u8; 32]); + Oracle::feed_values(account, vec![(key.clone(), rate)])?; + + // If feeding was successful, just use the feeded price to spare a read + let converted_asset_price = FixedNumber::try_from(rate) + .map_err(|_| DispatchError::Other("Failed to convert price"))?; + Ok(converted_asset_price) + }, + } + } +} + +parameter_types! { + pub const SellFee: Permill = Permill::from_percent(5); + pub const MinAmountToBuyout: Balance = 10 * MILLIUNIT; // 0.01 AMPE or 10_000_000_000 + // 24 hours in blocks (where average block time is 12 seconds) + pub const BuyoutPeriod: u32 = 7200; + // Maximum number of allowed currencies for buyout + pub const MaxAllowedBuyoutCurrencies: u32 = 20; +} + +impl treasury_buyout_extension::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Currencies; + type TreasuryAccount = AmplitudeTreasuryAccount; + type BuyoutPeriod = BuyoutPeriod; + type SellFee = SellFee; + type PriceGetter = OraclePriceGetter; + type MinAmountToBuyout = MinAmountToBuyout; + type MaxAllowedBuyoutCurrencies = MaxAllowedBuyoutCurrencies; + type WeightInfo = treasury_buyout_extension::default_weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type RelayChainCurrencyId = RelayChainCurrencyId; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime where @@ -1391,6 +1489,7 @@ construct_runtime!( RewardDistribution: reward_distribution::{Pallet, Call, Storage, Event} = 73, TokenAllowance: orml_currencies_allowance_extension::{Pallet, Storage, Call, Event} = 80, + TreasuryBuyoutExtension: treasury_buyout_extension::{Pallet, Storage, Call, Event} = 82, Farming: farming::{Pallet, Call, Storage, Event} = 90, @@ -1429,6 +1528,7 @@ mod benches { [pallet_xcm, PolkadotXcm] [orml_currencies_allowance_extension, TokenAllowance] + [treasury_buyout_extension, TreasuryBuyoutExtension] ); }