pallet_psm/
benchmarking.rs1use super::*;
21use crate::Pallet as Psm;
22use frame_benchmarking::v2::*;
23use frame_support::traits::{
24 fungible::{metadata::Inspect, Create as FungibleCreate, Inspect as FungibleInspect},
25 fungibles::{
26 Create as FungiblesCreate, Inspect as FungiblesInspect, Mutate as FungiblesMutate,
27 },
28 Get,
29};
30use frame_system::RawOrigin;
31use pallet::BalanceOf;
32use sp_runtime::{traits::Zero, Permill, Saturating};
33
34const ASSET_ID_OFFSET: u32 = 100;
37
38fn ensure_internal_setup<T: Config>() -> u8
43where
44 T::InternalAsset: FungibleCreate<T::AccountId>,
45{
46 let admin: T::AccountId = whitelisted_caller();
47 let _ = frame_system::Pallet::<T>::inc_providers(&admin);
48 if T::InternalAsset::minimum_balance().is_zero() {
49 let _ = T::InternalAsset::create(admin, true, 1u32.into());
50 }
51 let internal_decimals = T::InternalAsset::decimals();
52 if !crate::InternalDecimals::<T>::exists() {
53 crate::InternalDecimals::<T>::put(internal_decimals);
54 }
55 internal_decimals
56}
57
58fn setup_assets<T: Config>(n: u32) -> T::AssetId
68where
69 T::Fungibles: FungiblesCreate<T::AccountId>,
70 T::InternalAsset: FungibleCreate<T::AccountId>,
71{
72 let admin: T::AccountId = whitelisted_caller();
73 let _ = frame_system::Pallet::<T>::inc_providers(&admin);
74
75 let internal_decimals = ensure_internal_setup::<T>();
76
77 let target_id: T::AssetId = T::BenchmarkHelper::get_asset_id(ASSET_ID_OFFSET);
82 if !T::Fungibles::asset_exists(target_id.clone()) {
83 T::BenchmarkHelper::create_asset(target_id.clone(), &admin, internal_decimals);
84 }
85
86 crate::MaxPsmDebtOfTotal::<T>::put(Permill::from_percent(100));
87 for i in 0..n {
91 let id: T::AssetId = T::BenchmarkHelper::get_asset_id(ASSET_ID_OFFSET + i);
92 crate::ExternalAssets::<T>::insert(&id, CircuitBreakerLevel::AllEnabled);
93 crate::AssetCeilingWeight::<T>::insert(&id, Permill::from_percent(1));
94 crate::PsmDebt::<T>::insert(&id, BalanceOf::<T>::from(1u32));
95 }
96 crate::AssetCeilingWeight::<T>::insert(&target_id, Permill::from_percent(100));
99 crate::ExternalDecimals::<T>::insert(&target_id, internal_decimals);
100
101 target_id
102}
103
104#[benchmarks(
105 where
106 T::Fungibles: FungiblesCreate<T::AccountId>,
107 T::InternalAsset: FungibleCreate<T::AccountId>,
108)]
109mod benchmarks {
110 use super::*;
111
112 #[benchmark]
116 fn mint(n: Linear<1, { T::MaxExternalAssets::get() }>) -> Result<(), BenchmarkError> {
117 let caller: T::AccountId = whitelisted_caller();
118 let asset_id = setup_assets::<T>(n);
119 let mint_amount = T::MinSwapAmount::get().saturating_mul(10u32.into());
120
121 T::Fungibles::mint_into(asset_id.clone(), &caller, mint_amount.saturating_mul(2u32.into()))
122 .map_err(|_| BenchmarkError::Stop("Failed to fund caller"))?;
123
124 let psm_account = Psm::<T>::account_id();
125 let reserve_before = T::Fungibles::balance(asset_id.clone(), &psm_account);
126
127 #[extrinsic_call]
128 _(RawOrigin::Signed(caller.clone()), asset_id.clone(), mint_amount);
129
130 assert!(T::Fungibles::balance(asset_id, &psm_account) > reserve_before);
131 Ok(())
132 }
133
134 #[benchmark]
135 fn redeem() -> Result<(), BenchmarkError> {
136 let caller: T::AccountId = whitelisted_caller();
137 let asset_id = setup_assets::<T>(1);
138 let setup_amount = T::MinSwapAmount::get().saturating_mul(10u32.into());
139 let redeem_amount = T::MinSwapAmount::get();
140
141 T::Fungibles::mint_into(
142 asset_id.clone(),
143 &caller,
144 setup_amount.saturating_mul(2u32.into()),
145 )
146 .map_err(|_| BenchmarkError::Stop("Failed to fund caller"))?;
147 Psm::<T>::mint(RawOrigin::Signed(caller.clone()).into(), asset_id.clone(), setup_amount)
148 .map_err(|_| BenchmarkError::Stop("Failed to setup reserve via mint"))?;
149
150 let psm_account = Psm::<T>::account_id();
151 let reserve_before = T::Fungibles::balance(asset_id.clone(), &psm_account);
152
153 #[extrinsic_call]
154 _(RawOrigin::Signed(caller.clone()), asset_id.clone(), redeem_amount);
155
156 assert!(T::Fungibles::balance(asset_id, &psm_account) < reserve_before);
157 Ok(())
158 }
159
160 #[benchmark]
161 fn set_minting_fee() -> Result<(), BenchmarkError> {
162 let asset_id = setup_assets::<T>(1);
163 let new_fee = Permill::from_percent(2);
164
165 #[extrinsic_call]
166 _(RawOrigin::Root, asset_id.clone(), new_fee);
167
168 assert_eq!(crate::MintingFee::<T>::get(&asset_id), new_fee);
169 Ok(())
170 }
171
172 #[benchmark]
173 fn set_redemption_fee() -> Result<(), BenchmarkError> {
174 let asset_id = setup_assets::<T>(1);
175 let new_fee = Permill::from_percent(2);
176
177 #[extrinsic_call]
178 _(RawOrigin::Root, asset_id.clone(), new_fee);
179
180 assert_eq!(crate::RedemptionFee::<T>::get(&asset_id), new_fee);
181 Ok(())
182 }
183
184 #[benchmark]
185 fn set_max_psm_debt() -> Result<(), BenchmarkError> {
186 let new_ratio = Permill::from_percent(20);
187
188 #[extrinsic_call]
189 _(RawOrigin::Root, new_ratio);
190
191 assert_eq!(crate::MaxPsmDebtOfTotal::<T>::get(), new_ratio);
192 Ok(())
193 }
194
195 #[benchmark]
196 fn set_asset_status() -> Result<(), BenchmarkError> {
197 let asset_id = setup_assets::<T>(1);
198 let new_status = CircuitBreakerLevel::MintingDisabled;
199
200 #[extrinsic_call]
201 _(RawOrigin::Root, asset_id.clone(), new_status);
202
203 assert_eq!(crate::ExternalAssets::<T>::get(&asset_id), Some(new_status));
204 Ok(())
205 }
206
207 #[benchmark]
208 fn set_asset_ceiling_weight() -> Result<(), BenchmarkError> {
209 let asset_id = setup_assets::<T>(1);
210 let new_weight = Permill::from_percent(50);
211
212 #[extrinsic_call]
213 _(RawOrigin::Root, asset_id.clone(), new_weight);
214
215 assert_eq!(crate::AssetCeilingWeight::<T>::get(&asset_id), new_weight);
216 Ok(())
217 }
218 #[benchmark]
219 fn add_external_asset() -> Result<(), BenchmarkError> {
220 let internal_decimals = ensure_internal_setup::<T>();
223 let caller: T::AccountId = whitelisted_caller();
224 let new_asset_id: T::AssetId = T::BenchmarkHelper::get_asset_id(ASSET_ID_OFFSET);
225
226 T::BenchmarkHelper::create_asset(new_asset_id.clone(), &caller, internal_decimals);
227
228 #[extrinsic_call]
229 _(RawOrigin::Root, new_asset_id.clone());
230
231 assert!(crate::ExternalAssets::<T>::contains_key(&new_asset_id));
232 Ok(())
233 }
234
235 #[benchmark]
236 fn remove_external_asset() -> Result<(), BenchmarkError> {
237 let asset_id = setup_assets::<T>(1);
238 crate::PsmDebt::<T>::remove(&asset_id);
239
240 #[extrinsic_call]
241 _(RawOrigin::Root, asset_id.clone());
242
243 assert!(!crate::ExternalAssets::<T>::contains_key(&asset_id));
244 Ok(())
245 }
246
247 impl_benchmark_test_suite!(Psm, crate::mock::new_test_ext(), crate::mock::Test);
248}