1use crate::{types::*, BalanceSnapShots, Config, Pallet};
37
38use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
40use scale_info::TypeInfo;
41
42use frame_suite::{
44 assets::*,
45 base::Delimited,
46 misc::{Directive, Extent},
47 mutation::MutHandle,
48 virtuals::*,
49};
50
51use frame_support::{
53 pallet_prelude::NMapKey,
54 traits::tokens::{Fortitude, Precision},
55 Blake2_128Concat,
56};
57
58use sp_core::{ConstU32, Get};
60use sp_runtime::{Cow, DispatchError, Vec};
61
62pub fn deposit<'a, T: Config<I>, I: 'static>(
71 balance: &'a mut VirtualBalance<T, I>,
72 variant: &'a T::Position,
73 id: &'a Digest<T>,
74 value: &'a AssetOf<T, I>,
75 qualify: &'a DispatchPolicy,
76) -> Result<(AssetOf<T, I>, VirtualReceipt<T, I>), DispatchError> {
77 let input = <LazyInput<'a, T, I> as FromTag<_, Deposit>>::from_tag((
78 MutHandle::Borrowed(balance),
79 Cow::Borrowed(variant),
80 Cow::Borrowed(id),
81 Cow::Borrowed(value),
82 Cow::Borrowed(qualify),
83 ));
84
85 let raw = Pallet::<T, I>::deposit(input);
86
87 let Ok(result) = TryIntoTag::<_, Deposit>::try_into_tag(raw) else {
88 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
89 };
90
91 match result {
92 Ok((asset, receipt)) => Ok((asset.into_owned(), receipt.into_owned())),
93 Err(e) => Err(e.into()),
94 }
95}
96
97pub fn withdraw<'a, T: Config<I>, I: 'static>(
103 balance: &'a mut VirtualBalance<T, I>,
104 variant: &'a T::Position,
105 id: &'a Digest<T>,
106 receipt: &'a VirtualReceipt<T, I>,
107) -> Result<AssetOf<T, I>, DispatchError> {
108 let input = <LazyInput<'a, T, I> as FromTag<_, Withdraw>>::from_tag((
109 MutHandle::Borrowed(balance),
110 Cow::Borrowed(variant),
111 Cow::Borrowed(id),
112 Cow::Borrowed(receipt),
113 ));
114
115 let raw = Pallet::<T, I>::withdraw(input);
116
117 let Ok(result) = TryIntoTag::<_, Withdraw>::try_into_tag(raw) else {
118 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
119 };
120
121 match result {
122 Ok(v) => Ok(*v),
123 Err(e) => Err(e.into()),
124 }
125}
126
127pub fn mint<'a, T: Config<I>, I: 'static>(
133 balance: &'a mut VirtualBalance<T, I>,
134 variant: &'a T::Position,
135 id: &'a Digest<T>,
136 value: &'a AssetOf<T, I>,
137 qualify: &'a DispatchPolicy,
138) -> Result<AssetOf<T, I>, DispatchError> {
139 let input = <LazyInput<'a, T, I> as FromTag<_, Mint>>::from_tag((
140 MutHandle::Borrowed(balance),
141 Cow::Borrowed(variant),
142 Cow::Borrowed(id),
143 Cow::Borrowed(value),
144 Cow::Borrowed(qualify),
145 ));
146
147 let raw = Pallet::<T, I>::mint(input);
148
149 let Ok(result) = TryIntoTag::<_, Mint>::try_into_tag(raw) else {
150 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
151 };
152
153 match result {
154 Ok(v) => Ok(v.into_owned()),
155 Err(e) => Err(e.into()),
156 }
157}
158
159pub fn reap<'a, T: Config<I>, I: 'static>(
165 balance: &'a mut VirtualBalance<T, I>,
166 variant: &'a T::Position,
167 id: &'a Digest<T>,
168 value: &'a AssetOf<T, I>,
169 qualify: &'a DispatchPolicy,
170) -> Result<AssetOf<T, I>, DispatchError> {
171 let input = <LazyInput<'a, T, I> as FromTag<_, Reap>>::from_tag((
172 MutHandle::Borrowed(balance),
173 Cow::Borrowed(variant),
174 Cow::Borrowed(id),
175 Cow::Borrowed(value),
176 Cow::Borrowed(qualify),
177 ));
178
179 let raw = Pallet::<T, I>::reap(input);
180
181 let Ok(result) = TryIntoTag::<_, Reap>::try_into_tag(raw) else {
182 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
183 };
184
185 match result {
186 Ok(v) => Ok(v.into_owned()),
187 Err(e) => Err(e.into()),
188 }
189}
190
191#[allow(unused)]
197pub fn drain<'a, T: Config<I>, I: 'static>(
198 balance: &'a mut VirtualBalance<T, I>,
199 variant: &'a T::Position,
200 id: &'a Digest<T>,
201) -> Result<(), DispatchError> {
202 let input = <LazyInput<'a, T, I> as FromTag<_, Drain>>::from_tag((
203 MutHandle::Borrowed(balance),
204 Cow::Borrowed(variant),
205 Cow::Borrowed(id),
206 ));
207
208 let raw = <Pallet<T, I> as LazyBalance>::drain(input);
209
210 let Ok(result) = TryIntoTag::<_, Drain>::try_into_tag(raw) else {
211 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
212 };
213
214 match result {
215 Ok(_) => Ok(()),
216 Err(e) => Err(e.into()),
217 }
218}
219
220pub fn can_deposit<'a, T: Config<I>, I: 'static>(
226 balance: &'a VirtualBalance<T, I>,
227 variant: &'a T::Position,
228 id: &'a Digest<T>,
229 value: &'a AssetOf<T, I>,
230 qualify: &'a DispatchPolicy,
231) -> Result<(), DispatchError> {
232 let input = <LazyInput<'a, T, I> as FromTag<_, CanDeposit>>::from_tag((
233 Cow::Borrowed(balance),
234 Cow::Borrowed(variant),
235 Cow::Borrowed(id),
236 Cow::Borrowed(value),
237 Cow::Borrowed(qualify),
238 ));
239
240 let raw = Pallet::<T, I>::can_deposit(input);
241
242 let Ok(result) = TryIntoTag::<_, CanDeposit>::try_into_tag(raw) else {
243 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
244 };
245
246 match result {
247 Ok(_) => Ok(()),
248 Err(e) => Err(e.into()),
249 }
250}
251
252pub fn can_withdraw<'a, T: Config<I>, I: 'static>(
258 balance: &'a VirtualBalance<T, I>,
259 variant: &'a T::Position,
260 id: &'a Digest<T>,
261 receipt: &'a VirtualReceipt<T, I>,
262) -> Result<(), DispatchError> {
263 let input = <LazyInput<'a, T, I> as FromTag<_, CanWithdraw>>::from_tag((
264 Cow::Borrowed(balance),
265 Cow::Borrowed(variant),
266 Cow::Borrowed(id),
267 Cow::Borrowed(receipt),
268 ));
269
270 let raw = Pallet::<T, I>::can_withdraw(input);
271
272 let Ok(result) = TryIntoTag::<_, CanWithdraw>::try_into_tag(raw) else {
273 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
274 };
275
276 match result {
277 Ok(_) => Ok(()),
278 Err(e) => Err(e.into()),
279 }
280}
281
282pub fn can_mint<'a, T: Config<I>, I: 'static>(
288 balance: &'a VirtualBalance<T, I>,
289 variant: &'a T::Position,
290 id: &'a Digest<T>,
291 value: &'a AssetOf<T, I>,
292 qualify: &'a DispatchPolicy,
293) -> Result<(), DispatchError> {
294 let input = <LazyInput<'a, T, I> as FromTag<_, CanMint>>::from_tag((
295 Cow::Borrowed(balance),
296 Cow::Borrowed(variant),
297 Cow::Borrowed(id),
298 Cow::Borrowed(value),
299 Cow::Borrowed(qualify),
300 ));
301
302 let raw = Pallet::<T, I>::can_mint(input);
303
304 let Ok(result) = TryIntoTag::<_, CanMint>::try_into_tag(raw) else {
305 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
306 };
307
308 match result {
309 Ok(_) => Ok(()),
310 Err(e) => Err(e.into()),
311 }
312}
313
314pub fn can_reap<'a, T: Config<I>, I: 'static>(
320 balance: &'a VirtualBalance<T, I>,
321 variant: &'a T::Position,
322 id: &'a Digest<T>,
323 value: &'a AssetOf<T, I>,
324 qualify: &'a DispatchPolicy,
325) -> Result<(), DispatchError> {
326 let input = <LazyInput<'a, T, I> as FromTag<_, CanReap>>::from_tag((
327 Cow::Borrowed(balance),
328 Cow::Borrowed(variant),
329 Cow::Borrowed(id),
330 Cow::Borrowed(value),
331 Cow::Borrowed(qualify),
332 ));
333
334 let raw = Pallet::<T, I>::can_reap(input);
335
336 let Ok(result) = TryIntoTag::<_, CanReap>::try_into_tag(raw) else {
337 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
338 };
339
340 match result {
341 Ok(_) => Ok(()),
342 Err(e) => Err(e.into()),
343 }
344}
345
346pub fn balance_total<'a, T: Config<I>, I: 'static>(
351 balance: &'a VirtualBalance<T, I>,
352 variant: &'a T::Position,
353 id: &'a Digest<T>,
354) -> Result<AssetOf<T, I>, DispatchError> {
355 let input = <LazyInput<'a, T, I> as FromTag<_, TotalValue>>::from_tag((
356 Cow::Borrowed(balance),
357 Cow::Borrowed(variant),
358 Cow::Borrowed(id),
359 ));
360
361 let raw = Pallet::<T, I>::total_value(input);
362
363 let Ok(result) = TryIntoTag::<_, TotalValue>::try_into_tag(raw) else {
364 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
365 };
366
367 match result {
368 Ok(v) => Ok(*v),
369 Err(e) => Err(e.into()),
370 }
371}
372
373pub fn receipt_active_value<'a, T: Config<I>, I: 'static>(
378 balance: &'a VirtualBalance<T, I>,
379 variant: &'a T::Position,
380 id: &'a Digest<T>,
381 receipt: &'a VirtualReceipt<T, I>,
382) -> Result<AssetOf<T, I>, DispatchError> {
383 let input = <LazyInput<'a, T, I> as FromTag<_, ReceiptActiveValue>>::from_tag((
384 Cow::Borrowed(balance),
385 Cow::Borrowed(variant),
386 Cow::Borrowed(id),
387 Cow::Borrowed(receipt),
388 ));
389
390 let raw = Pallet::<T, I>::receipt_active_value(input);
391
392 let Ok(result) = TryIntoTag::<_, ReceiptActiveValue>::try_into_tag(raw) else {
393 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
394 };
395
396 match result {
397 Ok(v) => Ok(*v),
398 Err(e) => Err(e.into()),
399 }
400}
401
402pub fn receipt_deposit_value<'a, T: Config<I>, I: 'static>(
407 receipt: &'a VirtualReceipt<T, I>,
408) -> Result<AssetOf<T, I>, DispatchError> {
409 let input =
410 <LazyInput<'a, T, I> as FromTag<_, ReceiptDepositValue>>::from_tag(Cow::Borrowed(receipt));
411
412 let raw = Pallet::<T, I>::receipt_deposit_value(input);
413
414 let Ok(result) = TryIntoTag::<_, ReceiptDepositValue>::try_into_tag(raw) else {
415 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
416 };
417
418 match result {
419 Ok(v) => Ok(*v),
420 Err(e) => Err(e.into()),
421 }
422}
423
424pub fn has_deposits<'a, T: Config<I>, I: 'static>(
429 balance: &'a VirtualBalance<T, I>,
430 variant: &'a T::Position,
431 id: &'a Digest<T>,
432) -> Result<(), DispatchError> {
433 let input = <LazyInput<'a, T, I> as FromTag<_, HasDeposits>>::from_tag((
434 Cow::Borrowed(balance),
435 Cow::Borrowed(variant),
436 Cow::Borrowed(id),
437 ));
438
439 let raw = Pallet::<T, I>::has_deposits(input);
440
441 let Ok(result) = TryIntoTag::<_, HasDeposits>::try_into_tag(raw) else {
442 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
443 };
444
445 match result {
446 Ok(_) => Ok(()),
447 Err(e) => Err(e.into()),
448 }
449}
450
451pub fn deposit_limits_of<'a, T: Config<I>, I: 'static>(
457 balance: &'a VirtualBalance<T, I>,
458 variant: &'a T::Position,
459 id: &'a Digest<T>,
460 qualify: &'a DispatchPolicy,
461) -> Result<LimitsProduct<T, I>, DispatchError> {
462 let input = <LazyInput<'a, T, I> as FromTag<_, DepositLimits>>::from_tag((
463 Cow::Borrowed(balance),
464 Cow::Borrowed(variant),
465 Cow::Borrowed(id),
466 Cow::Borrowed(qualify),
467 ));
468
469 let raw = Pallet::<T, I>::deposit_limits(input);
470
471 let Ok(result) = TryIntoTag::<_, DepositLimits>::try_into_tag(raw) else {
472 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
473 };
474
475 match result {
476 Ok(v) => Ok(v.into_owned()),
477 Err(e) => Err(e.into()),
478 }
479}
480
481pub fn mint_limits_of<'a, T: Config<I>, I: 'static>(
487 balance: &'a VirtualBalance<T, I>,
488 variant: &'a T::Position,
489 id: &'a Digest<T>,
490 qualify: &'a DispatchPolicy,
491) -> Result<LimitsProduct<T, I>, DispatchError> {
492 let input = <LazyInput<'a, T, I> as FromTag<_, MintLimits>>::from_tag((
493 Cow::Borrowed(balance),
494 Cow::Borrowed(variant),
495 Cow::Borrowed(id),
496 Cow::Borrowed(qualify),
497 ));
498
499 let raw = Pallet::<T, I>::mint_limits(input);
500
501 let Ok(result) = TryIntoTag::<_, MintLimits>::try_into_tag(raw) else {
502 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
503 };
504
505 match result {
506 Ok(v) => Ok(v.into_owned()),
507 Err(e) => Err(e.into()),
508 }
509}
510
511pub fn reap_limits_of<'a, T: Config<I>, I: 'static>(
517 balance: &'a VirtualBalance<T, I>,
518 variant: &'a T::Position,
519 id: &'a Digest<T>,
520 qualify: &'a DispatchPolicy,
521) -> Result<LimitsProduct<T, I>, DispatchError> {
522 let input = <LazyInput<'a, T, I> as FromTag<_, ReapLimits>>::from_tag((
523 Cow::Borrowed(balance),
524 Cow::Borrowed(variant),
525 Cow::Borrowed(id),
526 Cow::Borrowed(qualify),
527 ));
528
529 let raw = Pallet::<T, I>::reap_limits(input);
530
531 let Ok(result) = TryIntoTag::<_, ReapLimits>::try_into_tag(raw) else {
532 return Err(crate::Error::<T, I>::CorruptedPlugin.into());
533 };
534
535 match result {
536 Ok(v) => Ok(v.into_owned()),
537 Err(e) => Err(e.into()),
538 }
539}
540
541impl<T, I> LazyBalance for Pallet<T, I>
546where
547 T: Config<I>,
548 I: 'static,
549{
550 type Asset = AssetOf<T, I>;
551 type Rational = T::Bias;
552 type Time = T::Time;
553
554 type Balance = VirtualBalance<T, I>;
555 type Variant = T::Position;
556 type Id = Digest<T>;
557 type Limits = LimitsProduct<T, I>;
558 type Subject = DispatchPolicy;
559
560 type SnapShot = VirtualSnapShot<T, I>;
561 type Receipt = VirtualReceipt<T, I>;
562
563 type Input<'a> = LazyInput<'a, T, I>;
564 type Output<'a> = LazyOutput<'a, T, I>;
565
566 type BalanceFamily<'a> = T::BalanceFamily<'a>;
567 type BalanceContext = T::BalanceContext;
568}
569
570pub trait ProductProvider<Asset, Rational, Time, Addon>:
583 VirtualDynExtensionSchema<Addon>
584 + VirtualDynBound<Asset>
585 + VirtualDynBound<Rational>
586 + VirtualDynBound<Time>
587where
588 Addon: DiscriminantTag,
589 Rational: DiscriminantTag,
590 Time: DiscriminantTag,
591 Asset: DiscriminantTag,
592{
593}
594
595impl<T, Asset, Rational, Time, Addon> ProductProvider<Asset, Rational, Time, Addon> for T
596where
597 T: VirtualDynExtensionSchema<Addon>
598 + VirtualDynBound<Asset>
599 + VirtualDynBound<Rational>
600 + VirtualDynBound<Time>,
601 Addon: DiscriminantTag,
602 Rational: DiscriminantTag,
603 Time: DiscriminantTag,
604 Asset: DiscriminantTag,
605{
606}
607
608#[derive(Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen)]
636#[codec(encode_bound(
637 Provider: ProductProvider<Asset, Rational, Time, Addon>,
638 <Provider as VirtualDynExtensionSchema<Addon>>::Repr: Delimited + Default
639))]
640#[codec(decode_bound(
641 Provider: ProductProvider<Asset, Rational, Time, Addon>,
642 <Provider as VirtualDynExtensionSchema<Addon>>::Repr: Delimited + Default
643))]
644#[codec(decode_with_mem_tracking_bound(
645 Provider: ProductProvider<Asset, Rational, Time, Addon>,
646 <Provider as VirtualDynExtensionSchema<Addon>>::Repr: Delimited + Default
647))]
648#[codec(mel_bound(
649 <Provider as VirtualDynExtensionSchema<Addon>>::Repr: MaxEncodedLen
650))]
651#[scale_info(skip_type_params(T, I, Provider, Asset, Rational, Time, Addon))]
652pub struct ProductType<T, I, Provider, Asset, Rational, Time, Addon>
653where
654 Provider: ProductProvider<Asset, Rational, Time, Addon>,
655 T: Config<I>,
656 I: 'static,
657 Addon: DiscriminantTag,
658 Rational: DiscriminantTag,
659 Time: DiscriminantTag,
660 Asset: DiscriminantTag,
661{
662 asset: SumDynType<AssetOf<T, I>, <Provider as VirtualDynBound<Asset>>::Bound>,
666
667 bias: SumDynType<T::Bias, <Provider as VirtualDynBound<Rational>>::Bound>,
671
672 time: SumDynType<T::Time, <Provider as VirtualDynBound<Time>>::Bound>,
676
677 addon: <Provider as VirtualDynExtensionSchema<Addon>>::Repr,
682}
683
684impl<T, I, Provider, Asset, Rational, Time, Addon> Clone
685 for ProductType<T, I, Provider, Asset, Rational, Time, Addon>
686where
687 Provider: ProductProvider<Asset, Rational, Time, Addon>,
688 T: Config<I>,
689 I: 'static,
690 Addon: DiscriminantTag,
691 Rational: DiscriminantTag,
692 Time: DiscriminantTag,
693 Asset: DiscriminantTag,
694{
695 fn clone(&self) -> Self {
696 Self {
697 asset: self.asset.clone(),
698 bias: self.bias.clone(),
699 time: self.time.clone(),
700 addon: self.addon.clone(),
701 }
702 }
703}
704
705impl<T, I, Provider, Asset, Rational, Time, Addon> core::fmt::Debug
706 for ProductType<T, I, Provider, Asset, Rational, Time, Addon>
707where
708 Provider: ProductProvider<Asset, Rational, Time, Addon>,
709 T: Config<I>,
710 I: 'static,
711 Addon: DiscriminantTag,
712 Rational: DiscriminantTag,
713 Time: DiscriminantTag,
714 Asset: DiscriminantTag,
715{
716 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
717 f.debug_struct("ProductType")
718 .field("asset", &self.asset)
719 .field("bias", &self.bias)
720 .field("time", &self.time)
721 .field("addon", &self.addon)
722 .finish()
723 }
724}
725
726impl<T, I, Provider, Asset, Rational, Time, Addon> Default
727 for ProductType<T, I, Provider, Asset, Rational, Time, Addon>
728where
729 Provider: ProductProvider<Asset, Rational, Time, Addon>,
730 T: Config<I>,
731 I: 'static,
732 Addon: DiscriminantTag,
733 Rational: DiscriminantTag,
734 Time: DiscriminantTag,
735 Asset: DiscriminantTag,
736{
737 fn default() -> Self {
738 Self {
739 asset: Default::default(),
740 bias: Default::default(),
741 time: Default::default(),
742 addon: Default::default(),
743 }
744 }
745}
746
747impl<T, I, Provider, Asset, Rational, Time, Addon> PartialEq
748 for ProductType<T, I, Provider, Asset, Rational, Time, Addon>
749where
750 Provider: ProductProvider<Asset, Rational, Time, Addon>,
751 T: Config<I>,
752 I: 'static,
753 Addon: DiscriminantTag,
754 Rational: DiscriminantTag,
755 Time: DiscriminantTag,
756 Asset: DiscriminantTag,
757{
758 fn eq(&self, other: &Self) -> bool {
759 self.asset == other.asset
760 && self.bias == other.bias
761 && self.time == other.time
762 && self.addon == other.addon
763 }
764}
765
766impl<T, I, Provider, Asset, Rational, Time, Addon> Eq
767 for ProductType<T, I, Provider, Asset, Rational, Time, Addon>
768where
769 Provider: ProductProvider<Asset, Rational, Time, Addon>,
770 T: Config<I>,
771 I: 'static,
772 Addon: DiscriminantTag,
773 Rational: DiscriminantTag,
774 Time: DiscriminantTag,
775 Asset: DiscriminantTag,
776{
777}
778
779macro_rules! impl_v_field {
790 (
791 $tag:ty,
792 $field:ident,
793 $product:ty,
794 $asset:ty,
795 $rational:ty,
796 $time:ty,
797 $addon:ty,
798 $value:ty
799 ) => {
800 impl<T, I, Provider> VirtualDynField<$tag> for $product
801 where
802 Provider: ProductProvider<$asset, $rational, $time, $addon>,
803 T: Config<I>,
804 I: 'static,
805 {
806 type None = ();
807 type Some = $value;
808 type Many = Vec<$value>;
809 type Repr = SumDynType<$value, <Provider as VirtualDynBound<$tag>>::Bound>;
810
811 fn access(&self) -> Self::Repr {
812 self.$field.clone()
813 }
814
815 fn mutate(&mut self, v: Self::Repr) {
816 self.$field = v
817 }
818
819 fn len(&self) -> usize {
820 match &self.$field {
821 SumDynType::None => 0,
822 SumDynType::Some(_) => 1,
823 SumDynType::Many(v) => v.len(),
824 }
825 }
826
827 fn min(&self) -> usize {
828 match &self.$field {
829 SumDynType::None => 0,
830 SumDynType::Some(_) => 1,
831 SumDynType::Many(_) => 0,
832 }
833 }
834
835 fn max(&self) -> usize {
836 match &self.$field {
837 SumDynType::None => 0,
838 SumDynType::Some(_) => 1,
839 SumDynType::Many(_) => {
840 <Provider as VirtualDynBound<$tag>>::Bound::get() as usize
841 }
842 }
843 }
844 }
845 };
846}
847
848macro_rules! impl_v_ext {
853 (
854 $tag:ty,
855 $field:ident,
856 $product:ty,
857 $asset:ty,
858 $rational:ty,
859 $time:ty,
860 $addon:ty
861 ) => {
862 impl<T, I, Provider> VirtualDynExtension<$tag> for $product
863 where
864 Provider: ProductProvider<$asset, $rational, $time, $addon>,
865 T: Config<I>,
866 I: 'static,
867 {
868 type TypesVia = Provider;
869
870 fn access(&self) -> <Provider as VirtualDynExtensionSchema<$addon>>::Repr {
871 self.$field.clone()
872 }
873
874 fn mutate(&mut self, v: <Provider as VirtualDynExtensionSchema<$addon>>::Repr) {
875 self.$field = v
876 }
877 }
878 };
879}
880
881macro_rules! impl_product_alloc {
887 (
888 $asset:ty,
889 $rational:ty,
890 $time:ty,
891 $addon:ty
892 ) => {
893
894 impl_v_field!(
895 $asset,
896 asset,
897 ProductType<T,I,Provider,$asset,$rational,$time,$addon>,
898 $asset,
899 $rational,
900 $time,
901 $addon,
902 AssetOf<T,I>
903 );
904
905 impl_v_field!(
906 $rational,
907 bias,
908 ProductType<T,I,Provider,$asset,$rational,$time,$addon>,
909 $asset,
910 $rational,
911 $time,
912 $addon,
913 T::Bias
914 );
915
916 impl_v_field!(
917 $time,
918 time,
919 ProductType<T,I,Provider,$asset,$rational,$time,$addon>,
920 $asset,
921 $rational,
922 $time,
923 $addon,
924 T::Time
925 );
926
927 impl_v_ext!(
928 $addon,
929 addon,
930 ProductType<T,I,Provider,$asset,$rational,$time,$addon>,
931 $asset,
932 $rational,
933 $time,
934 $addon
935 );
936 };
937}
938
939impl_product_alloc!(BalanceAsset, BalanceRational, BalanceTime, BalanceAddon);
940
941impl_product_alloc!(SnapShotAsset, SnapShotRational, SnapShotTime, SnapShotAddon);
942
943impl_product_alloc!(ReceiptAsset, ReceiptRational, ReceiptTime, ReceiptAddon);
944
945type LazyBalanceOf<T, I> = VirtualBalance<T, I>;
951
952type LazyReceiptOf<T, I> = VirtualReceipt<T, I>;
954
955type LazyAssetOf<T, I> = AssetOf<T, I>;
957
958type LazyVariantOf<T, I> = <Pallet<T, I> as LazyBalance>::Variant;
960
961type LazyIdOf<T, I> = <Pallet<T, I> as LazyBalance>::Id;
963
964type LazyErrorOf<T, I> = <Context<Pallet<T, I>> as VirtualError<LazyBalanceError>>::Error;
966
967macro_rules! lazy_input {
979 (
980 $(
981 $variant:ident (
982 $( $field:ident : $ty:ty ),* $(,)?
983 )
984 ),* $(,)?
985 ) => {
986
987 pub enum LazyInput<'a, T, I>
988 where
989 T: Config<I>,
990 I: 'static,
991 {
992 $(
993 $variant( $( $ty ),* ),
994 )*
995 }
996
997 $(
998 #[allow(unused_parens)]
999 impl<'a, T, I>
1000 FromTag<( $( $ty ),* ), $variant>
1001 for LazyInput<'a, T, I>
1002 where
1003 T: Config<I>,
1004 I: 'static,
1005 {
1006 fn from_tag(t: ( $( $ty ),* )) -> Self {
1007 let ( $( $field ),* ) = t;
1008 LazyInput::$variant( $( $field ),* )
1009 }
1010 }
1011
1012 #[allow(unused_parens)]
1013 impl<'a, T, I>
1014 TryIntoTag<( $( $ty ),* ), $variant>
1015 for LazyInput<'a, T, I>
1016 where
1017 T: Config<I>,
1018 I: 'static,
1019 {
1020 type Error = ();
1021
1022 fn try_into_tag(self)
1023 -> Result<( $( $ty ),* ), Self::Error>
1024 {
1025 match self {
1026 LazyInput::$variant( $( $field ),* ) =>
1027 Ok(( $( $field ),* )),
1028 _ => Err(()),
1029 }
1030 }
1031 }
1032 )*
1033 };
1034}
1035
1036lazy_input! {
1037
1038 Deposit(
1039 balance: MutHandle<'a, LazyBalanceOf<T, I>>,
1040 variant: Cow<'a, LazyVariantOf<T, I>>,
1041 id: Cow<'a, LazyIdOf<T, I>>,
1042 asset: Cow<'a, LazyAssetOf<T, I>>,
1043 subject: Cow<'a, DispatchPolicy>,
1044 ),
1045
1046 Mint(
1047 balance: MutHandle<'a, LazyBalanceOf<T, I>>,
1048 variant: Cow<'a, LazyVariantOf<T, I>>,
1049 id: Cow<'a, LazyIdOf<T, I>>,
1050 asset: Cow<'a, LazyAssetOf<T, I>>,
1051 subject: Cow<'a, DispatchPolicy>,
1052 ),
1053
1054 Reap(
1055 balance: MutHandle<'a, LazyBalanceOf<T, I>>,
1056 variant: Cow<'a, LazyVariantOf<T, I>>,
1057 id: Cow<'a, LazyIdOf<T, I>>,
1058 asset: Cow<'a, LazyAssetOf<T, I>>,
1059 subject: Cow<'a, DispatchPolicy>,
1060 ),
1061
1062 Drain(
1063 balance: MutHandle<'a, LazyBalanceOf<T, I>>,
1064 variant: Cow<'a, LazyVariantOf<T, I>>,
1065 id: Cow<'a, LazyIdOf<T, I>>,
1066 ),
1067
1068 Withdraw(
1069 balance: MutHandle<'a, LazyBalanceOf<T, I>>,
1070 variant: Cow<'a, LazyVariantOf<T, I>>,
1071 id: Cow<'a, LazyIdOf<T, I>>,
1072 receipt: Cow<'a, LazyReceiptOf<T, I>>,
1073 ),
1074
1075 CanDeposit(
1076 balance: Cow<'a, LazyBalanceOf<T, I>>,
1077 variant: Cow<'a, LazyVariantOf<T, I>>,
1078 id: Cow<'a, LazyIdOf<T, I>>,
1079 asset: Cow<'a, LazyAssetOf<T, I>>,
1080 subject: Cow<'a, DispatchPolicy>,
1081 ),
1082
1083 CanMint(
1084 balance: Cow<'a, LazyBalanceOf<T, I>>,
1085 variant: Cow<'a, LazyVariantOf<T, I>>,
1086 id: Cow<'a, LazyIdOf<T, I>>,
1087 asset: Cow<'a, LazyAssetOf<T, I>>,
1088 subject: Cow<'a, DispatchPolicy>,
1089 ),
1090
1091 CanReap(
1092 balance: Cow<'a, LazyBalanceOf<T, I>>,
1093 variant: Cow<'a, LazyVariantOf<T, I>>,
1094 id: Cow<'a, LazyIdOf<T, I>>,
1095 asset: Cow<'a, LazyAssetOf<T, I>>,
1096 subject: Cow<'a, DispatchPolicy>,
1097 ),
1098
1099 CanWithdraw(
1100 balance: Cow<'a, LazyBalanceOf<T, I>>,
1101 variant: Cow<'a, LazyVariantOf<T, I>>,
1102 id: Cow<'a, LazyIdOf<T, I>>,
1103 receipt: Cow<'a, LazyReceiptOf<T, I>>,
1104 ),
1105
1106 TotalValue(
1107 balance: Cow<'a, LazyBalanceOf<T, I>>,
1108 variant: Cow<'a, LazyVariantOf<T, I>>,
1109 id: Cow<'a, LazyIdOf<T, I>>,
1110 ),
1111
1112 ReceiptActiveValue(
1113 balance: Cow<'a, LazyBalanceOf<T, I>>,
1114 variant: Cow<'a, LazyVariantOf<T, I>>,
1115 id: Cow<'a, LazyIdOf<T, I>>,
1116 receipt: Cow<'a, LazyReceiptOf<T, I>>,
1117 ),
1118
1119 HasDeposits(
1120 balance: Cow<'a, LazyBalanceOf<T, I>>,
1121 variant: Cow<'a, LazyVariantOf<T, I>>,
1122 id: Cow<'a, LazyIdOf<T, I>>,
1123 ),
1124
1125 ReceiptDepositValue(
1126 receipt: Cow<'a, LazyReceiptOf<T, I>>,
1127 ),
1128
1129 DepositLimits(
1130 balance: Cow<'a, LazyBalanceOf<T, I>>,
1131 variant: Cow<'a, LazyVariantOf<T, I>>,
1132 id: Cow<'a, LazyIdOf<T, I>>,
1133 subject: Cow<'a, DispatchPolicy>,
1134 ),
1135
1136 MintLimits(
1137 balance: Cow<'a, LazyBalanceOf<T, I>>,
1138 variant: Cow<'a, LazyVariantOf<T, I>>,
1139 id: Cow<'a, LazyIdOf<T, I>>,
1140 subject: Cow<'a, DispatchPolicy>,
1141 ),
1142
1143 ReapLimits(
1144 balance: Cow<'a, LazyBalanceOf<T, I>>,
1145 variant: Cow<'a, LazyVariantOf<T, I>>,
1146 id: Cow<'a, LazyIdOf<T, I>>,
1147 subject: Cow<'a, DispatchPolicy>,
1148 ),
1149
1150}
1151
1152macro_rules! lazy_output {
1160 (
1161 $(
1162 $variant:ident ( $ty:ty )
1163 ),* $(,)?
1164 ) => {
1165
1166 pub enum LazyOutput<'a, T, I>
1167 where
1168 T: Config<I>,
1169 I: 'static,
1170 {
1171 $(
1172 $variant($ty),
1173 )*
1174 }
1175
1176 $(
1177 impl<'a, T, I> FromTag<$ty, $variant>
1178 for LazyOutput<'a, T, I>
1179 where
1180 T: Config<I>,
1181 I: 'static,
1182 {
1183 fn from_tag(t: $ty) -> Self {
1184 Self::$variant(t)
1185 }
1186 }
1187
1188 impl<'a, T, I> TryIntoTag<$ty, $variant>
1189 for LazyOutput<'a, T, I>
1190 where
1191 T: Config<I>,
1192 I: 'static,
1193 {
1194 type Error = ();
1195
1196 fn try_into_tag(self) -> Result<$ty, Self::Error> {
1197 match self {
1198 Self::$variant(i) => Ok(i),
1199 _ => Err(()),
1200 }
1201 }
1202 }
1203 )*
1204 };
1205}
1206
1207lazy_output! {
1208 Deposit(Result<(Cow<'a, AssetOf<T, I>>, Cow<'a, LazyReceiptOf<T, I>>), LazyErrorOf<T, I>>),
1209 Mint(Result<Cow<'a, AssetOf<T, I>>, LazyErrorOf<T, I>>),
1210 Reap(Result<Cow<'a, AssetOf<T, I>>, LazyErrorOf<T, I>>),
1211 Withdraw(Result<Cow<'a, LazyAssetOf<T, I>>, LazyErrorOf<T, I>>),
1212 Drain(Result<Cow<'a, AssetOf<T, I>>, LazyErrorOf<T, I>>),
1213 CanDeposit(Result<(), LazyErrorOf<T, I>>),
1214 CanMint(Result<(), LazyErrorOf<T, I>>),
1215 CanReap(Result<(), LazyErrorOf<T, I>>),
1216 CanWithdraw(Result<(), LazyErrorOf<T, I>>),
1217 TotalValue(Result<Cow<'a, LazyAssetOf<T, I>>, LazyErrorOf<T, I>>),
1218 ReceiptActiveValue(Result<Cow<'a, LazyAssetOf<T, I>>, LazyErrorOf<T, I>>),
1219 HasDeposits(Result<(), LazyErrorOf<T, I>>),
1220 ReceiptDepositValue(Result<Cow<'a, LazyAssetOf<T, I>>, LazyErrorOf<T, I>>),
1221 DepositLimits(Result<Cow<'a, LimitsProduct<T, I>>, LazyErrorOf<T, I>>),
1222 MintLimits(Result<Cow<'a, LimitsProduct<T, I>>, LazyErrorOf<T, I>>),
1223 ReapLimits(Result<Cow<'a, LimitsProduct<T, I>>, LazyErrorOf<T, I>>),
1224}
1225
1226impl<T, I> VirtualNMap<VirtualBalance<T, I>, SnapShotStorage> for Pallet<T, I>
1238where
1239 T: Config<I>,
1240 I: 'static,
1241{
1242 type Key = (Digest<T>, T::Position, T::Time);
1243
1244 type Value = VirtualSnapShot<T, I>;
1245
1246 type KeyGen = (
1247 NMapKey<Blake2_128Concat, Digest<T>>,
1248 NMapKey<Blake2_128Concat, T::Position>,
1249 NMapKey<Blake2_128Concat, T::Time>,
1250 );
1251
1252 type Map = BalanceSnapShots<T, I>;
1253
1254 type Query = Option<VirtualSnapShot<T, I>>;
1255}
1256
1257#[derive(Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen)]
1268#[scale_info(skip_type_params(T, I))]
1269pub struct LimitsProduct<T, I>
1270where
1271 T: Config<I>,
1272 I: 'static,
1273{
1274 asset: SumDynType<AssetOf<T, I>, ConstU32<3>>,
1278}
1279
1280impl<T, I> Clone for LimitsProduct<T, I>
1281where
1282 T: Config<I>,
1283 I: 'static,
1284 SumDynType<AssetOf<T, I>, ConstU32<3>>: Clone,
1285{
1286 fn clone(&self) -> Self {
1287 Self {
1288 asset: self.asset.clone(),
1289 }
1290 }
1291}
1292
1293impl<T, I> core::fmt::Debug for LimitsProduct<T, I>
1294where
1295 T: Config<I>,
1296 I: 'static,
1297 SumDynType<AssetOf<T, I>, ConstU32<3>>: core::fmt::Debug,
1298{
1299 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1300 f.debug_struct("LimitsProduct")
1301 .field("asset", &self.asset)
1302 .finish()
1303 }
1304}
1305
1306impl<T, I> Default for LimitsProduct<T, I>
1307where
1308 T: Config<I>,
1309 I: 'static,
1310 SumDynType<AssetOf<T, I>, ConstU32<3>>: Default,
1311{
1312 fn default() -> Self {
1313 Self {
1314 asset: Default::default(),
1315 }
1316 }
1317}
1318
1319impl<T, I> core::cmp::PartialEq for LimitsProduct<T, I>
1320where
1321 T: Config<I>,
1322 I: 'static,
1323 SumDynType<AssetOf<T, I>, ConstU32<3>>: PartialEq,
1324{
1325 fn eq(&self, other: &Self) -> bool {
1326 self.asset == other.asset
1327 }
1328}
1329
1330impl<T, I> core::cmp::Eq for LimitsProduct<T, I>
1331where
1332 T: Config<I>,
1333 I: 'static,
1334 SumDynType<AssetOf<T, I>, ConstU32<3>>: Eq,
1335{
1336}
1337
1338impl<T: Config<I>, I: 'static> VirtualDynField<LimitsAsset> for LimitsProduct<T, I> {
1339 type None = ();
1340
1341 type Some = AssetOf<T, I>;
1342
1343 type Many = Vec<AssetOf<T, I>>;
1344
1345 type Repr = SumDynType<AssetOf<T, I>, ConstU32<3>>;
1346
1347 fn access(&self) -> Self::Repr {
1348 self.asset.clone()
1349 }
1350
1351 fn mutate(&mut self, v: Self::Repr) {
1352 self.asset = v
1353 }
1354
1355 fn len(&self) -> usize {
1356 match &self.asset {
1357 SumDynType::None => 0,
1358 SumDynType::Some(_) => 1,
1359 SumDynType::Many(v) => v.len(),
1360 }
1361 }
1362
1363 fn min(&self) -> usize {
1364 match &self.asset {
1365 SumDynType::None => 0,
1366 SumDynType::Some(_) => 1,
1367 SumDynType::Many(_) => 0,
1368 }
1369 }
1370
1371 fn max(&self) -> usize {
1372 match &self.asset {
1373 SumDynType::None => 0,
1374 SumDynType::Some(_) => 1,
1375 SumDynType::Many(_) => 3,
1376 }
1377 }
1378}
1379
1380impl<T: Config<I>, I: 'static> VirtualDynBound<LimitsAsset> for LimitsProduct<T, I> {
1381 type Bound = ConstU32<3>;
1382}
1383
1384impl<T: Config<I>, I: 'static> Extent<LimitsAsset> for LimitsProduct<T, I> {
1385 type Scalar = AssetOf<T, I>;
1386
1387 fn minimum(&self) -> Option<Self::Scalar> {
1388 self.index_get(0)
1389 }
1390
1391 fn maximum(&self) -> Option<Self::Scalar> {
1392 self.index_get(1)
1393 }
1394
1395 fn optimal(&self) -> Option<Self::Scalar> {
1396 self.index_get(3)
1397 }
1398
1399 fn none() -> Self {
1400 Default::default()
1401 }
1402}
1403
1404impl<T: Config<I>, I: 'static> Extent for LimitsProduct<T, I> {
1405 type Scalar = AssetOf<T, I>;
1406
1407 fn minimum(&self) -> Option<Self::Scalar> {
1408 self.index_get(0)
1409 }
1410
1411 fn maximum(&self) -> Option<Self::Scalar> {
1412 self.index_get(1)
1413 }
1414
1415 fn optimal(&self) -> Option<Self::Scalar> {
1416 self.index_get(3)
1417 }
1418
1419 fn none() -> Self {
1420 Default::default()
1421 }
1422}
1423
1424#[derive(
1436 Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen, Debug,
1437)]
1438pub struct DispatchPolicy {
1439 pub precise: bool,
1441
1442 pub force: bool,
1444}
1445
1446impl Directive for DispatchPolicy {
1447 fn precision(&self) -> Precision {
1448 if self.precise {
1449 return Precision::Exact;
1450 };
1451 Precision::BestEffort
1452 }
1453
1454 fn fortitude(&self) -> Fortitude {
1455 if self.force {
1456 return Fortitude::Force;
1457 };
1458 Fortitude::Polite
1459 }
1460
1461 fn new(precision: Precision, fortitude: Fortitude) -> Self {
1462 Self {
1463 precise: matches!(precision, Precision::Exact),
1464 force: matches!(fortitude, Fortitude::Force),
1465 }
1466 }
1467}
1468
1469impl Default for DispatchPolicy {
1470 fn default() -> Self {
1471 Self {
1472 precise: false,
1473 force: false,
1474 }
1475 }
1476}