feat: initialize Kurdistan SDK - independent fork of Polkadot SDK

This commit is contained in:
2025-12-13 15:44:15 +03:00
commit e4778b4576
6838 changed files with 1847450 additions and 0 deletions
+46
View File
@@ -0,0 +1,46 @@
[package]
name = "snowbridge-test-utils"
description = "Snowbridge test utilities"
version = "0.1.0"
authors = ["Snowfork <contact@snowfork.com>"]
edition.workspace = true
repository.workspace = true
license = "Apache-2.0"
categories = ["cryptography::cryptocurrencies"]
[lints]
workspace = true
[package.metadata.pezkuwi-sdk]
exclude-from-umbrella = true
[dependencies]
bp-relayers = { workspace = true, default-features = true }
codec = { workspace = true, default-features = true }
frame-benchmarking = { optional = true, workspace = true, default-features = true }
frame-support = { workspace = true, default-features = true }
frame-system = { workspace = true, default-features = true }
pallet-asset-conversion = { workspace = true, default-features = true }
scale-info = { features = [
"derive",
], workspace = true, default-features = true }
snowbridge-core = { workspace = true, default-features = true }
snowbridge-outbound-queue-primitives = { workspace = true, default-features = true }
sp-core = { workspace = true, default-features = true }
xcm = { workspace = true, default-features = true }
xcm-builder = { workspace = true, default-features = true }
xcm-executor = { workspace = true, default-features = true }
[features]
runtime-benchmarks = [
"bp-relayers/runtime-benchmarks",
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-asset-conversion/runtime-benchmarks",
"snowbridge-core/runtime-benchmarks",
"snowbridge-outbound-queue-primitives/runtime-benchmarks",
"xcm-builder/runtime-benchmarks",
"xcm-executor/runtime-benchmarks",
"xcm/runtime-benchmarks",
]
+11
View File
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
pub mod mock_converter;
pub mod mock_inbound_queue;
pub mod mock_origin;
pub mod mock_outbound_queue;
pub mod mock_rewards;
pub mod mock_swap_executor;
pub mod mock_xcm;
pub const FAILING_NONCE: u64 = 3;
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use codec::Encode;
use frame_support::sp_runtime::traits::MaybeConvert;
use snowbridge_core::TokenIdOf;
use sp_core::H256;
use std::{cell::RefCell, collections::HashMap};
use xcm::{
latest::InteriorLocation,
prelude::{Location, Reanchorable},
};
use xcm_executor::traits::ConvertLocation;
thread_local! {
pub static IDENTIFIER_TO_LOCATION: RefCell<HashMap<H256, Location>> = RefCell::new(HashMap::new());
pub static LOCATION_TO_IDENTIFIER: RefCell<HashMap<Vec<u8>, H256>> = RefCell::new(HashMap::new());
}
pub fn add_location_override(location: Location, ethereum: Location, bh_context: InteriorLocation) {
let (token_id, reanchored_location) = reanchor_to_ethereum(location, ethereum, bh_context);
IDENTIFIER_TO_LOCATION.with(|b| b.borrow_mut().insert(token_id, reanchored_location.clone()));
LOCATION_TO_IDENTIFIER.with(|b| b.borrow_mut().insert(reanchored_location.encode(), token_id));
}
pub fn reanchor_to_ethereum(
location: Location,
ethereum: Location,
bh_context: InteriorLocation,
) -> (H256, Location) {
let mut reanchored_lol = location.clone();
let _ = reanchored_lol.reanchor(&ethereum, &bh_context);
let token_id = TokenIdOf::convert_location(&reanchored_lol).unwrap();
(token_id, reanchored_lol)
}
pub struct LocationIdConvert;
impl MaybeConvert<H256, Location> for LocationIdConvert {
fn maybe_convert(id: H256) -> Option<Location> {
IDENTIFIER_TO_LOCATION.with(|b| b.borrow().get(&id).and_then(|l| Option::from(l.clone())))
}
}
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use crate::FAILING_NONCE;
use snowbridge_core::reward::{AddTip, AddTipError};
pub struct MockOkInboundQueue;
impl AddTip for MockOkInboundQueue {
fn add_tip(nonce: u64, _amount: u128) -> Result<(), AddTipError> {
// Force an error condition
if nonce == FAILING_NONCE {
return Err(AddTipError::NonceConsumed);
}
Ok(())
}
}
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
// A stripped-down version of pallet-xcm that only inserts an XCM origin into the runtime
#[frame_support::pallet]
pub mod pallet_xcm_origin {
use codec::DecodeWithMemTracking;
use frame_support::{
pallet_prelude::*,
traits::{Contains, OriginTrait},
};
use xcm::latest::prelude::*;
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeOrigin: From<Origin> + From<<Self as frame_system::Config>::RuntimeOrigin>;
}
// Insert this custom Origin into the aggregate RuntimeOrigin
#[pallet::origin]
#[derive(
PartialEq,
Eq,
Clone,
Encode,
Decode,
DecodeWithMemTracking,
RuntimeDebug,
TypeInfo,
MaxEncodedLen,
)]
pub struct Origin(pub Location);
impl From<Location> for Origin {
fn from(location: Location) -> Origin {
Origin(location)
}
}
/// `EnsureOrigin` implementation succeeding with a `Location` value to recognize and
/// filter the contained location
pub struct EnsureXcm<F>(PhantomData<F>);
impl<O: OriginTrait + From<Origin>, F: Contains<Location>> EnsureOrigin<O> for EnsureXcm<F>
where
O::PalletsOrigin: From<Origin> + TryInto<Origin, Error = O::PalletsOrigin>,
{
type Success = Location;
fn try_origin(outer: O) -> Result<Self::Success, O> {
outer.try_with_caller(|caller| {
caller.try_into().and_then(|o| match o {
Origin(location) if F::contains(&location) => Ok(location),
o => Err(o.into()),
})
})
}
#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin() -> Result<O, ()> {
Ok(O::from(Origin(Location::here().into())))
}
}
}
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use crate::FAILING_NONCE;
use snowbridge_core::reward::{AddTip, AddTipError};
use snowbridge_outbound_queue_primitives::{
v1::{Fee, Message as MessageV1, SendMessage as SendMessageV1},
v2::{Message, SendMessage},
SendMessageFeeProvider,
};
use sp_core::H256;
pub struct MockOkOutboundQueue;
impl SendMessage for MockOkOutboundQueue {
type Ticket = ();
fn validate(
_: &Message,
) -> Result<Self::Ticket, snowbridge_outbound_queue_primitives::SendError> {
Ok(())
}
fn deliver(_: Self::Ticket) -> Result<H256, snowbridge_outbound_queue_primitives::SendError> {
Ok(H256::zero())
}
}
impl SendMessageFeeProvider for MockOkOutboundQueue {
type Balance = u128;
fn local_fee() -> Self::Balance {
0
}
}
impl AddTip for MockOkOutboundQueue {
fn add_tip(nonce: u64, _amount: u128) -> Result<(), AddTipError> {
if nonce == FAILING_NONCE {
return Err(AddTipError::NonceConsumed);
}
Ok(())
}
}
pub struct MockOkOutboundQueueV1;
impl SendMessageV1 for MockOkOutboundQueueV1 {
type Ticket = ();
fn validate(
_: &MessageV1,
) -> Result<
(Self::Ticket, Fee<<Self as SendMessageFeeProvider>::Balance>),
snowbridge_outbound_queue_primitives::SendError,
> {
Ok(((), Fee::from((0, 0))))
}
fn deliver(_: Self::Ticket) -> Result<H256, snowbridge_outbound_queue_primitives::SendError> {
Ok(H256::zero())
}
}
impl SendMessageFeeProvider for MockOkOutboundQueueV1 {
type Balance = u128;
fn local_fee() -> Self::Balance {
0
}
}
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use bp_relayers::{PaymentProcedure, RewardLedger, RewardsAccountOwner, RewardsAccountParams};
use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use frame_support::{pallet_prelude::DispatchResult, parameter_types, sp_runtime};
use scale_info::TypeInfo;
use xcm::opaque::latest::Location;
/// Showcasing that we can handle multiple different rewards with the same pallet.
#[derive(
Clone,
Copy,
Debug,
Decode,
DecodeWithMemTracking,
Encode,
Eq,
MaxEncodedLen,
PartialEq,
TypeInfo,
)]
pub enum BridgeReward {
/// Rewards for Snowbridge.
Snowbridge,
}
pub struct MockPaymentProcedure;
// Provide a no-op or mock implementation for the required trait
impl PaymentProcedure<sp_runtime::AccountId32, RewardsAccountParams<u64>, u128>
for MockPaymentProcedure
{
type Error = DispatchResult;
type Beneficiary = Location;
fn pay_reward(
_who: &sp_runtime::AccountId32,
_reward_params: bp_relayers::RewardsAccountParams<u64>,
_reward_balance: u128,
_beneficiary: Self::Beneficiary,
) -> Result<(), Self::Error> {
Ok(())
}
}
impl From<BridgeReward> for RewardsAccountParams<u64> {
fn from(_bridge_reward: BridgeReward) -> Self {
RewardsAccountParams::new(1, [0; 4], RewardsAccountOwner::ThisChain)
}
}
parameter_types! {
pub static RegisteredRewardsCount: u128 = 0;
pub static RegisteredRewardAmount: u128 = 0;
}
pub struct MockRewardLedger;
impl RewardLedger<sp_runtime::AccountId32, BridgeReward, u128> for MockRewardLedger {
fn register_reward(
_relayer: &sp_runtime::AccountId32,
_reward: BridgeReward,
reward_balance: u128,
) {
RegisteredRewardsCount::set(RegisteredRewardsCount::get().saturating_add(1));
RegisteredRewardAmount::set(reward_balance);
}
}
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use frame_support::pallet_prelude::DispatchError;
use pallet_asset_conversion::Swap;
use xcm::opaque::latest::Location;
pub struct SwapExecutor;
pub const TRIGGER_SWAP_ERROR_AMOUNT: u128 = 12345;
impl<AccountId> Swap<AccountId> for SwapExecutor
where
AccountId: AsRef<[u8; 32]>,
{
type Balance = u128;
type AssetKind = Location;
fn max_path_len() -> u32 {
2
}
fn swap_exact_tokens_for_tokens(
_sender: AccountId,
_path: Vec<Self::AssetKind>,
amount_in: Self::Balance,
_amount_out_min: Option<Self::Balance>,
_send_to: AccountId,
_keep_alive: bool,
) -> Result<Self::Balance, DispatchError> {
// Special case for testing SwapError:
// If amount_in is exactly 12345, return an error
if amount_in == TRIGGER_SWAP_ERROR_AMOUNT {
return Err(DispatchError::Other("Swap failed for test"));
}
Ok(1_000_000_000u128)
}
fn swap_tokens_for_exact_tokens(
_sender: AccountId,
_path: Vec<Self::AssetKind>,
_amount_out: Self::Balance,
_amount_in_max: Option<Self::Balance>,
_send_to: AccountId,
_keep_alive: bool,
) -> Result<Self::Balance, DispatchError> {
unimplemented!()
}
}
@@ -0,0 +1,157 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use codec::Encode;
use core::cell::RefCell;
use xcm::prelude::*;
use xcm_executor::{
traits::{FeeManager, FeeReason, TransactAsset},
AssetsInHolding,
};
thread_local! {
pub static IS_WAIVED: RefCell<Vec<FeeReason>> = RefCell::new(vec![]);
pub static SENDER_OVERRIDE: RefCell<Option<(
fn(
&mut Option<Location>,
&mut Option<Xcm<()>>,
) -> Result<(Xcm<()>, Assets), SendError>,
fn(
Xcm<()>,
) -> Result<XcmHash, SendError>,
)>> = RefCell::new(None);
pub static CHARGE_FEES_OVERRIDE: RefCell<Option<
fn(Location, Assets) -> xcm::latest::Result
>> = RefCell::new(None);
}
#[allow(dead_code)]
pub fn set_fee_waiver(waived: Vec<FeeReason>) {
IS_WAIVED.with(|l| l.replace(waived));
}
#[allow(dead_code)]
pub fn set_sender_override(
validate: fn(&mut Option<Location>, &mut Option<Xcm<()>>) -> SendResult<Xcm<()>>,
deliver: fn(Xcm<()>) -> Result<XcmHash, SendError>,
) {
SENDER_OVERRIDE.with(|x| x.replace(Some((validate, deliver))));
}
#[allow(dead_code)]
pub fn clear_sender_override() {
SENDER_OVERRIDE.with(|x| x.replace(None));
}
#[allow(dead_code)]
pub fn set_charge_fees_override(charge_fees: fn(Location, Assets) -> xcm::latest::Result) {
CHARGE_FEES_OVERRIDE.with(|x| x.replace(Some(charge_fees)));
}
#[allow(dead_code)]
pub fn clear_charge_fees_override() {
CHARGE_FEES_OVERRIDE.with(|x| x.replace(None));
}
/// Mock XCM sender with an overridable `validate` and `deliver` function.
pub struct MockXcmSender;
impl SendXcm for MockXcmSender {
type Ticket = Xcm<()>;
fn validate(
dest: &mut Option<Location>,
xcm: &mut Option<Xcm<()>>,
) -> SendResult<Self::Ticket> {
let r: SendResult<Self::Ticket> = SENDER_OVERRIDE.with(|s| {
if let Some((ref f, _)) = &*s.borrow() {
f(dest, xcm)
} else {
Ok((xcm.take().unwrap(), Assets::default()))
}
});
r
}
fn deliver(ticket: Self::Ticket) -> Result<XcmHash, SendError> {
let r: Result<XcmHash, SendError> = SENDER_OVERRIDE.with(|s| {
if let Some((_, ref f)) = &*s.borrow() {
f(ticket)
} else {
let hash = ticket.using_encoded(sp_core::hashing::blake2_256);
Ok(hash)
}
});
r
}
}
/// Mock XCM transactor that always succeeds
pub struct SuccessfulTransactor;
impl TransactAsset for SuccessfulTransactor {
fn can_check_in(_origin: &Location, _what: &Asset, _context: &XcmContext) -> XcmResult {
Ok(())
}
fn can_check_out(_dest: &Location, _what: &Asset, _context: &XcmContext) -> XcmResult {
Ok(())
}
fn deposit_asset(_what: &Asset, _who: &Location, _context: Option<&XcmContext>) -> XcmResult {
Ok(())
}
fn withdraw_asset(
_what: &Asset,
_who: &Location,
_context: Option<&XcmContext>,
) -> Result<AssetsInHolding, XcmError> {
Ok(AssetsInHolding::default())
}
fn internal_transfer_asset(
_what: &Asset,
_from: &Location,
_to: &Location,
_context: &XcmContext,
) -> Result<AssetsInHolding, XcmError> {
Ok(AssetsInHolding::default())
}
}
pub enum Weightless {}
impl PreparedMessage for Weightless {
fn weight_of(&self) -> Weight {
unreachable!();
}
}
/// Mock the XCM executor with an overridable `charge_fees` function.
pub struct MockXcmExecutor;
impl<C> ExecuteXcm<C> for MockXcmExecutor {
type Prepared = Weightless;
fn prepare(_: Xcm<C>, _: Weight) -> Result<Self::Prepared, InstructionError> {
unreachable!()
}
fn execute(_: impl Into<Location>, _: Self::Prepared, _: &mut XcmHash, _: Weight) -> Outcome {
unreachable!()
}
fn charge_fees(location: impl Into<Location>, assets: Assets) -> xcm::latest::Result {
let r: xcm::latest::Result = CHARGE_FEES_OVERRIDE.with(|s| {
if let Some(ref f) = &*s.borrow() {
f(location.into(), assets)
} else {
Ok(())
}
});
r
}
}
impl FeeManager for MockXcmExecutor {
fn is_waived(_: Option<&Location>, r: FeeReason) -> bool {
IS_WAIVED.with(|l| l.borrow().contains(&r))
}
fn handle_fee(_: Assets, _: Option<&XcmContext>, _: FeeReason) {}
}