1use crate::pallet::{
2 InboxFee, InboxFeesOnHold, InboxFeesOnHoldStartAt, InboxResponseMessageWeightTags,
3 InboxResponses, OutboxFee, OutboxFeesOnHold, OutboxFeesOnHoldStartAt,
4};
5use crate::{BalanceOf, Config, Error, Pallet};
6use frame_support::traits::fungible::{Balanced, Mutate};
7use frame_support::traits::tokens::{Fortitude, Precision, Preservation};
8use frame_support::weights::WeightToFee;
9use sp_core::Get;
10use sp_messenger::endpoint::{CollectedFee, Endpoint};
11use sp_messenger::messages::{ChainId, ChannelId, MessageId, Nonce};
12use sp_messenger::OnXDMRewards;
13use sp_runtime::traits::{CheckedAdd, CheckedMul, CheckedSub, Zero};
14use sp_runtime::{DispatchError, DispatchResult, Saturating};
15
16impl<T: Config> Pallet<T> {
17 #[inline]
19 pub(crate) fn collect_fees_for_message_v1(
20 sender: &T::AccountId,
21 endpoint: &Endpoint,
22 ) -> Result<CollectedFee<BalanceOf<T>>, DispatchError> {
23 let handler = T::get_endpoint_handler(endpoint).ok_or(Error::<T>::NoMessageHandler)?;
24
25 let fee_multiplier = BalanceOf::<T>::from(T::FeeMultiplier::get());
26
27 let dst_chain_inbox_execution_fee =
30 T::AdjustedWeightToFee::weight_to_fee(&handler.message_weight());
31
32 let dst_chain_fee = dst_chain_inbox_execution_fee
34 .checked_mul(&fee_multiplier)
35 .ok_or(Error::<T>::BalanceOverflow)?;
36
37 let src_chain_outbox_response_execution_fee =
40 T::AdjustedWeightToFee::weight_to_fee(&handler.message_response_weight());
41
42 let src_chain_fee = src_chain_outbox_response_execution_fee
44 .checked_mul(&fee_multiplier)
45 .ok_or(Error::<T>::BalanceOverflow)?;
46
47 let total_fees = dst_chain_fee
49 .checked_add(&src_chain_fee)
50 .ok_or(Error::<T>::BalanceOverflow)?;
51 T::Currency::burn_from(
52 sender,
53 total_fees,
54 Preservation::Preserve,
55 Precision::Exact,
56 Fortitude::Polite,
57 )?;
58
59 Ok(CollectedFee {
60 src_chain_fee,
61 dst_chain_fee,
62 })
63 }
64
65 pub(crate) fn reward_operators_for_inbox_execution(
69 dst_chain_id: ChainId,
70 channel_id: ChannelId,
71 latest_confirmed_nonce: Option<Nonce>,
72 ) -> DispatchResult {
73 if latest_confirmed_nonce.is_none() {
74 return Ok(());
75 }
76
77 let mut current_nonce = latest_confirmed_nonce;
78 let mut inbox_fees = BalanceOf::<T>::zero();
79 let on_hold_start_at_nonce =
80 InboxFeesOnHoldStartAt::<T>::get(channel_id).unwrap_or(Nonce::MAX);
81 let mut on_hold_inbox_fees = BalanceOf::<T>::zero();
82 while let Some(nonce) = current_nonce {
83 if InboxResponses::<T>::take((dst_chain_id, channel_id, nonce)).is_none() {
84 break;
88 }
89
90 InboxResponseMessageWeightTags::<T>::remove((dst_chain_id, (channel_id, nonce)));
92
93 if let Some(inbox_fee) = InboxFee::<T>::take((dst_chain_id, (channel_id, nonce))) {
95 inbox_fees = inbox_fees.saturating_add(inbox_fee);
96 if on_hold_start_at_nonce <= nonce {
97 on_hold_inbox_fees = on_hold_inbox_fees.saturating_add(inbox_fee);
98 }
99 }
100
101 current_nonce = nonce.checked_sub(Nonce::one())
102 }
103
104 if !inbox_fees.is_zero() {
105 if !on_hold_inbox_fees.is_zero() {
106 InboxFeesOnHold::<T>::mutate(|inbox_fees_on_hold| {
107 *inbox_fees_on_hold = inbox_fees_on_hold
108 .checked_sub(&on_hold_inbox_fees)
109 .ok_or(Error::<T>::BalanceUnderflow)?;
110
111 let imbalance = T::Currency::rescind(on_hold_inbox_fees);
114 core::mem::forget(imbalance);
115
116 Ok::<(), Error<T>>(())
117 })?;
118 }
119
120 Self::reward_operators(inbox_fees);
121 }
122
123 Ok(())
124 }
125
126 pub(crate) fn reward_operators_for_outbox_execution(
127 dst_chain_id: ChainId,
128 message_id: MessageId,
129 ) -> DispatchResult {
130 if let Some(fee) = OutboxFee::<T>::take((dst_chain_id, message_id)) {
131 let update_on_hold = OutboxFeesOnHoldStartAt::<T>::get(message_id.0)
132 .map(|start_at_nonce| start_at_nonce <= message_id.1)
133 .unwrap_or(false);
134 if update_on_hold {
135 OutboxFeesOnHold::<T>::mutate(|outbox_fees_on_hold| {
136 *outbox_fees_on_hold = outbox_fees_on_hold
137 .checked_sub(&fee)
138 .ok_or(Error::<T>::BalanceUnderflow)?;
139
140 let imbalance = T::Currency::rescind(fee);
143 core::mem::forget(imbalance);
144
145 Ok::<(), Error<T>>(())
146 })?;
147 }
148
149 Self::reward_operators(fee);
150 }
151 Ok(())
152 }
153
154 fn reward_operators(reward: BalanceOf<T>) {
156 T::OnXDMRewards::on_xdm_rewards(reward)
157 }
158}