Skip to content

Commit 718814d

Browse files
committed
fix ci
1 parent 98f53f4 commit 718814d

2 files changed

Lines changed: 268 additions & 0 deletions

File tree

.github/workflows/check-code.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,17 @@ jobs:
360360
~/.cargo/git/db/
361361
key: ${{ github.job }}-${{ github.ref }}-${{ matrix.runtime }}-${{ hashFiles('**/Cargo.lock') }}
362362

363+
- name: Install frame-omni-bencher
364+
run: |
365+
docker run --rm \
366+
-v "${GITHUB_WORKSPACE}:/workspace" \
367+
-v "${HOME}/.cargo/registry/index:${{ env.CARGO_HOME }}/registry/index" \
368+
-v "${HOME}/.cargo/registry/cache:${{ env.CARGO_HOME }}/registry/cache" \
369+
-v "${HOME}/.cargo/git/db:${{ env.CARGO_HOME }}/git/db" \
370+
-w /workspace \
371+
paritytech/ci-unified:bullseye-1.81.0 \
372+
bash -c "cargo install frame-omni-bencher --locked"
373+
363374
- name: Run runtime benchmarks
364375
run: |
365376
docker run --rm \
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
// KILT Blockchain – <https://kilt.io>
2+
// Copyright (C) 2025, KILT Foundation
3+
4+
// The KILT Blockchain is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
9+
// The KILT Blockchain is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
// If you feel like getting in touch with us, you can do so at <hello@kilt.io>
18+
19+
use frame_support::{
20+
ensure,
21+
traits::{fungible::Mutate, tokens::Preservation},
22+
weights::WeightToFee as WeightToFeeT,
23+
};
24+
use sp_core::Get;
25+
use sp_runtime::traits::Zero;
26+
use sp_std::marker::PhantomData;
27+
use xcm::v4::{Asset, AssetId, Error, Location, Weight, XcmContext, XcmHash};
28+
use xcm_executor::{traits::WeightTrader, AssetsInHolding};
29+
30+
const LOG_TARGET: &str = "xcm::bKILT::UsingComponentsForBKILT";
31+
32+
/// Type implementing [WeightTrader] that allows paying for XCM fees when
33+
/// reserve transferring the remote asset of the on-chain switch pair.
34+
///
35+
/// This trader is required in case there is no other mechanism to pay for
36+
/// fees when transferring such an asset to this chain.
37+
///
38+
/// Any unused fee is transferred from the switch pair pool account to the
39+
/// specified account.
40+
#[derive(Default, Debug, Clone)]
41+
pub struct UsingComponentsForSwitchPairRemoteAsset<T, I, WeightToFee, FeeDestinationAccount>
42+
where
43+
T: Config<I>,
44+
I: 'static,
45+
FeeDestinationAccount: Get<T::AccountId>,
46+
{
47+
remaining_weight: Weight,
48+
remaining_fungible_balance: u128,
49+
consumed_xcm_hash: Option<XcmHash>,
50+
remote_asset_id: AssetId,
51+
remote_location: Location,
52+
_phantom: PhantomData<(WeightToFee, I, FeeDestinationAccount)>,
53+
}
54+
55+
impl<T, I, WeightToFee, FeeDestinationAccount> PartialEq
56+
for UsingComponentsForSwitchPairRemoteAsset<T, I, WeightToFee, FeeDestinationAccount>
57+
where
58+
T: Config<I>,
59+
I: 'static,
60+
FeeDestinationAccount: Get<T::AccountId>,
61+
{
62+
fn eq(&self, other: &Self) -> bool {
63+
self.remaining_weight == other.remaining_weight
64+
&& self.remaining_fungible_balance == other.remaining_fungible_balance
65+
&& self.consumed_xcm_hash == other.consumed_xcm_hash
66+
&& self.remote_asset_id == other.remote_asset_id
67+
&& self.remote_location == other.remote_location
68+
}
69+
}
70+
71+
impl<T, I, WeightToFee, FeeDestinationAccount> WeightTrader
72+
for UsingComponentsForSwitchPairRemoteAsset<T, I, WeightToFee, FeeDestinationAccount>
73+
where
74+
T: Config<I>,
75+
I: 'static,
76+
FeeDestinationAccount: Get<T::AccountId>,
77+
WeightToFee: WeightToFeeT<Balance = u128>,
78+
{
79+
fn new() -> Self {
80+
let switch_pair = SwitchPair::<T, I>::get();
81+
Self {
82+
consumed_xcm_hash: None,
83+
remaining_fungible_balance: Zero::zero(),
84+
remaining_weight: Zero::zero(),
85+
_phantom: PhantomData,
86+
}
87+
}
88+
89+
fn buy_weight(
90+
&mut self,
91+
weight: Weight,
92+
payment: AssetsInHolding,
93+
context: &XcmContext,
94+
) -> Result<AssetsInHolding, Error> {
95+
log::info!(
96+
target: LOG_TARGET,
97+
"buy_weight {:?}, {:?}, {:?}",
98+
weight,
99+
payment,
100+
context
101+
);
102+
103+
// Prevent re-using the same trader more than once.
104+
ensure!(self.consumed_xcm_hash.is_none(), Error::NotWithdrawable);
105+
// Asset not relevant if no switch pair is set or if not enabled.
106+
let switch_pair = self.switch_pair.as_ref().ok_or(Error::AssetNotFound)?;
107+
ensure!(switch_pair.is_enabled(), Error::AssetNotFound);
108+
109+
let amount = WeightToFee::weight_to_fee(&weight);
110+
111+
let switch_pair_remote_asset_v4: AssetId = switch_pair.remote_asset_id.clone().try_into().map_err(|e| {
112+
log::error!(
113+
target: LOG_TARGET,
114+
"Failed to convert stored asset ID {:?} into v4 AssetId with error {:?}",
115+
switch_pair.remote_asset_id,
116+
e
117+
);
118+
Error::FailedToTransactAsset("Failed to convert switch pair asset ID into required version.")
119+
})?;
120+
121+
let required: Asset = (switch_pair_remote_asset_v4, amount).into();
122+
let unused = payment.checked_sub(required.clone()).map_err(|_| Error::TooExpensive)?;
123+
124+
// Set link to XCM message ID only if this is the trader used.
125+
log::trace!(target: LOG_TARGET, "Required {:?} - unused {:?}", required, unused);
126+
self.consumed_xcm_hash = Some(context.message_id);
127+
self.remaining_fungible_balance = self.remaining_fungible_balance.saturating_add(amount);
128+
self.remaining_weight = self.remaining_weight.saturating_add(weight);
129+
130+
Ok(unused)
131+
}
132+
133+
fn refund_weight(&mut self, weight: Weight, context: &XcmContext) -> Option<Asset> {
134+
log::trace!(
135+
target: LOG_TARGET,
136+
"UsingComponents::refund_weight weight: {:?}, context: {:?}",
137+
weight,
138+
context
139+
);
140+
141+
// Ensure we refund in the same trader we took fees from.
142+
if Some(context.message_id) != self.consumed_xcm_hash {
143+
return None;
144+
};
145+
146+
let Some(switch_pair) = &self.switch_pair else {
147+
log::error!(target: LOG_TARGET, "Stored switch pair should not be None, but it is.");
148+
return None;
149+
};
150+
if !switch_pair.is_enabled() {
151+
return None;
152+
}
153+
154+
let switch_pair_remote_asset_v4: AssetId = switch_pair
155+
.remote_asset_id
156+
.clone()
157+
.try_into()
158+
.map_err(|e| {
159+
log::error!(
160+
target: LOG_TARGET,
161+
"Failed to convert stored asset ID {:?} into v4 AssetId with error {:?}",
162+
switch_pair.remote_asset_id,
163+
e
164+
);
165+
Error::FailedToTransactAsset("Failed to convert switch pair asset ID into required version.")
166+
})
167+
.ok()?;
168+
169+
let weight_to_refund = weight.min(self.remaining_weight);
170+
let amount_for_weight_to_refund = WeightToFee::weight_to_fee(&weight_to_refund);
171+
// We can only refund up to the remaining balance of this weigher.
172+
let amount_to_refund = amount_for_weight_to_refund.min(self.remaining_fungible_balance);
173+
174+
self.consumed_xcm_hash = None;
175+
self.remaining_fungible_balance = self.remaining_fungible_balance.saturating_sub(amount_to_refund);
176+
self.remaining_weight = self.remaining_weight.saturating_sub(weight_to_refund);
177+
178+
if amount_to_refund > 0 {
179+
log::trace!(
180+
target: LOG_TARGET,
181+
"Refund amount {:?}",
182+
(switch_pair_remote_asset_v4.clone(), amount_to_refund)
183+
);
184+
Some((switch_pair_remote_asset_v4, amount_to_refund).into())
185+
} else {
186+
log::trace!(target: LOG_TARGET, "No refund");
187+
None
188+
}
189+
}
190+
}
191+
192+
// Move any unused asset from the switch pool account to the specified account,
193+
// and update the remote balance with the difference since we know we control
194+
// the full amount on the remote location.
195+
impl<T, I, WeightToFee, FeeDestinationAccount> Drop
196+
for UsingComponentsForSwitchPairRemoteAsset<T, I, WeightToFee, FeeDestinationAccount>
197+
where
198+
T: Config<I>,
199+
I: 'static,
200+
FeeDestinationAccount: Get<T::AccountId>,
201+
{
202+
fn drop(&mut self) {
203+
log::trace!(
204+
target: LOG_TARGET,
205+
"Drop with remaining {:?}",
206+
(
207+
self.consumed_xcm_hash,
208+
self.remaining_fungible_balance,
209+
self.remaining_weight,
210+
&self.switch_pair
211+
)
212+
);
213+
214+
// Nothing to refund if this trader was not called or if the leftover balance is
215+
// zero.
216+
if let Some(switch_pair) = &self.switch_pair {
217+
// We don't care if the pool is enabled, since we're sending all non-refunded
218+
// weight to the configured destination account (e.g., treasury).
219+
if self.remaining_fungible_balance > Zero::zero() {
220+
let Ok(remaining_balance_as_local_currency) = LocalCurrencyBalanceOf::<T, I>::try_from(self.remaining_fungible_balance).inspect_err(|_| {
221+
log::error!(target: LOG_TARGET, "Failed to convert remaining balance {:?} to local currency balance", self.remaining_fungible_balance);
222+
}) else { return; };
223+
224+
// No error should ever be thrown from inside this block.
225+
let transfer_result = <T::LocalCurrency as Mutate<T::AccountId>>::transfer(
226+
&switch_pair.pool_account,
227+
&FeeDestinationAccount::get(),
228+
remaining_balance_as_local_currency,
229+
Preservation::Preserve,
230+
).inspect_err(|_| {
231+
log::error!(target: LOG_TARGET, "Failed to transfer unused balance {:?} from switch pair pool account {:?} to specified account {:?}", remaining_balance_as_local_currency, switch_pair.pool_account, FeeDestinationAccount::get());
232+
});
233+
234+
debug_assert!(
235+
transfer_result.is_ok(),
236+
"Transferring from pool account to fee destination failed."
237+
);
238+
239+
// No error should ever be thrown from inside this block.
240+
SwitchPair::<T, I>::mutate(|entry| {
241+
let Some(existing_switch_pair) = entry.as_mut() else {
242+
log::error!(target: LOG_TARGET, "Stored switch pair should not be None but it is.");
243+
return;
244+
};
245+
existing_switch_pair
246+
.try_process_incoming_switch(self.remaining_fungible_balance)
247+
.unwrap_or_else(|_| {
248+
log::error!(
249+
target: LOG_TARGET,
250+
"Failed to increase balance of remote sovereign account due to overflow."
251+
);
252+
});
253+
});
254+
}
255+
}
256+
}
257+
}

0 commit comments

Comments
 (0)