From 91d4c155b6f8fe3511d778fa4c5b57d371f70362 Mon Sep 17 00:00:00 2001 From: Sergej Date: Fri, 26 Apr 2024 08:49:44 +0200 Subject: [PATCH 01/29] Region AssetTransactor --- runtime/regionx/src/lib.rs | 4 +++- runtime/regionx/src/xcm_config.rs | 22 ++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/runtime/regionx/src/lib.rs b/runtime/regionx/src/lib.rs index 334a7340..d70b59a1 100644 --- a/runtime/regionx/src/lib.rs +++ b/runtime/regionx/src/lib.rs @@ -235,6 +235,8 @@ const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, ); +pub const CORETIME_CHAIN_PARA_ID: u32 = 1005; + /// The version information used to identify this runtime when compiled natively. #[cfg(feature = "std")] pub fn native_version() -> NativeVersion { @@ -584,7 +586,7 @@ impl StateMachineHeightProviderT for StateMachineHeightProvider { } parameter_types! { - pub const CoretimeChain: StateMachine = StateMachine::Kusama(1005); // coretime-kusama + pub const CoretimeChain: StateMachine = StateMachine::Kusama(CORETIME_CHAIN_PARA_ID); // coretime-kusama } impl pallet_regions::Config for Runtime { diff --git a/runtime/regionx/src/xcm_config.rs b/runtime/regionx/src/xcm_config.rs index 51f55038..a1c041cc 100644 --- a/runtime/regionx/src/xcm_config.rs +++ b/runtime/regionx/src/xcm_config.rs @@ -15,7 +15,8 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, + Regions, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, + CORETIME_CHAIN_PARA_ID, }; use frame_support::{ match_types, parameter_types, @@ -32,12 +33,16 @@ use xcm_builder::{ FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, + TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, NonFungibleAdapter, }; use xcm_executor::XcmExecutor; parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); + pub const BrokerPalletLocation: MultiLocation = MultiLocation { + parents: 1, + interior: X2(Parachain(CORETIME_CHAIN_PARA_ID), PalletInstance(50)) + }; pub const RelayNetwork: Option = None; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); @@ -69,6 +74,19 @@ pub type LocalAssetTransactor = FungibleAdapter< (), >; +pub type RegionTransactor = NonFungibleAdapter< + // Use this non-fungible implementation: + Regions, + // This adapter will handle coretime regions from the broker pallet. + IsConcrete, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We don't track any teleports. + (), +>; + /// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, /// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can /// biases the kind of local `Origin` it will become. From bd86a628a44fe84b3ac9204904ca98f8a6b241a9 Mon Sep 17 00:00:00 2001 From: Sergej Date: Sat, 4 May 2024 15:56:14 +0200 Subject: [PATCH 02/29] workaround --- runtime/regionx/src/adapter.rs | 323 ++++++++++++++++++++++++++++++ runtime/regionx/src/lib.rs | 5 + runtime/regionx/src/xcm_config.rs | 4 +- 3 files changed, 330 insertions(+), 2 deletions(-) create mode 100644 runtime/regionx/src/adapter.rs diff --git a/runtime/regionx/src/adapter.rs b/runtime/regionx/src/adapter.rs new file mode 100644 index 00000000..9d43078a --- /dev/null +++ b/runtime/regionx/src/adapter.rs @@ -0,0 +1,323 @@ +// TODO: remove this file +// This has been temporarily added here because the NonFungibleAdapter is in release 1.7.0 +// or later, but we cannot update to that version now because of ISMP. + +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Adapters to work with [`frame_support::traits::tokens::nonfungible`] through XCM. + +use xcm_builder::MintLocation; +use frame_support::{ + ensure, + traits::{tokens::nonfungible, Get}, +}; +use sp_std::{marker::PhantomData, prelude::*, result}; +use xcm::latest::prelude::*; +use xcm_executor::traits::{ + ConvertLocation, Error as MatchError, MatchesNonFungible, TransactAsset, +}; + +const LOG_TARGET: &str = "xcm::nonfungible_adapter"; + +pub struct NonFungibleTransferAdapter( + PhantomData<(Asset, Matcher, AccountIdConverter, AccountId)>, +); +impl< + Asset: nonfungible::Transfer, + Matcher: MatchesNonFungible, + AccountIdConverter: ConvertLocation, + AccountId: Clone, // can't get away without it since Currency is generic over it. + > TransactAsset for NonFungibleTransferAdapter +{ + fn transfer_asset( + what: &MultiAsset, + from: &MultiLocation, + to: &MultiLocation, + context: &XcmContext, + ) -> result::Result { + log::trace!( + target: LOG_TARGET, + "transfer_asset what: {:?}, from: {:?}, to: {:?}, context: {:?}", + what, + from, + to, + context, + ); + // Check we handle this asset. + let instance = Matcher::matches_nonfungible(what).ok_or(MatchError::AssetNotHandled)?; + let destination = AccountIdConverter::convert_location(to) + .ok_or(MatchError::AccountIdConversionFailed)?; + Asset::transfer(&instance, &destination) + .map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; + Ok(what.clone().into()) + } +} + +pub struct NonFungibleMutateAdapter( + PhantomData<(Asset, Matcher, AccountIdConverter, AccountId, CheckingAccount)>, +); + +impl< + Asset: nonfungible::Mutate, + Matcher: MatchesNonFungible, + AccountIdConverter: ConvertLocation, + AccountId: Clone + Eq, // can't get away without it since Currency is generic over it. + CheckingAccount: Get>, + > NonFungibleMutateAdapter +{ + fn can_accrue_checked(instance: Asset::ItemId) -> XcmResult { + ensure!(Asset::owner(&instance).is_none(), XcmError::NotDepositable); + Ok(()) + } + fn can_reduce_checked(checking_account: AccountId, instance: Asset::ItemId) -> XcmResult { + // This is an asset whose teleports we track. + let owner = Asset::owner(&instance); + ensure!(owner == Some(checking_account), XcmError::NotWithdrawable); + ensure!(Asset::can_transfer(&instance), XcmError::NotWithdrawable); + Ok(()) + } + fn accrue_checked(checking_account: AccountId, instance: Asset::ItemId) { + let ok = Asset::mint_into(&instance, &checking_account).is_ok(); + debug_assert!(ok, "`mint_into` cannot generally fail; qed"); + } + fn reduce_checked(instance: Asset::ItemId) { + let ok = Asset::burn(&instance, None).is_ok(); + debug_assert!(ok, "`can_check_in` must have returned `true` immediately prior; qed"); + } +} + +impl< + Asset: nonfungible::Mutate, + Matcher: MatchesNonFungible, + AccountIdConverter: ConvertLocation, + AccountId: Clone + Eq, // can't get away without it since Currency is generic over it. + CheckingAccount: Get>, + > TransactAsset + for NonFungibleMutateAdapter +{ + fn can_check_in(_origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult { + log::trace!( + target: LOG_TARGET, + "can_check_in origin: {:?}, what: {:?}, context: {:?}", + _origin, + what, + context, + ); + // Check we handle this asset. + let instance = Matcher::matches_nonfungible(what).ok_or(MatchError::AssetNotHandled)?; + match CheckingAccount::get() { + // We track this asset's teleports to ensure no more come in than have gone out. + Some((checking_account, MintLocation::Local)) => + Self::can_reduce_checked(checking_account, instance), + // We track this asset's teleports to ensure no more go out than have come in. + Some((_, MintLocation::NonLocal)) => Self::can_accrue_checked(instance), + _ => Ok(()), + } + } + + fn check_in(_origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) { + log::trace!( + target: LOG_TARGET, + "check_in origin: {:?}, what: {:?}, context: {:?}", + _origin, + what, + context, + ); + if let Some(instance) = Matcher::matches_nonfungible(what) { + match CheckingAccount::get() { + // We track this asset's teleports to ensure no more come in than have gone out. + Some((_, MintLocation::Local)) => Self::reduce_checked(instance), + // We track this asset's teleports to ensure no more go out than have come in. + Some((checking_account, MintLocation::NonLocal)) => + Self::accrue_checked(checking_account, instance), + _ => (), + } + } + } + + fn can_check_out(_dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult { + log::trace!( + target: LOG_TARGET, + "can_check_out dest: {:?}, what: {:?}, context: {:?}", + _dest, + what, + context, + ); + // Check we handle this asset. + let instance = Matcher::matches_nonfungible(what).ok_or(MatchError::AssetNotHandled)?; + match CheckingAccount::get() { + // We track this asset's teleports to ensure no more come in than have gone out. + Some((_, MintLocation::Local)) => Self::can_accrue_checked(instance), + // We track this asset's teleports to ensure no more go out than have come in. + Some((checking_account, MintLocation::NonLocal)) => + Self::can_reduce_checked(checking_account, instance), + _ => Ok(()), + } + } + + fn check_out(_dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) { + log::trace!( + target: LOG_TARGET, + "check_out dest: {:?}, what: {:?}, context: {:?}", + _dest, + what, + context, + ); + if let Some(instance) = Matcher::matches_nonfungible(what) { + match CheckingAccount::get() { + // We track this asset's teleports to ensure no more come in than have gone out. + Some((checking_account, MintLocation::Local)) => + Self::accrue_checked(checking_account, instance), + // We track this asset's teleports to ensure no more go out than have come in. + Some((_, MintLocation::NonLocal)) => Self::reduce_checked(instance), + _ => (), + } + } + } + + fn deposit_asset( + what: &MultiAsset, + who: &MultiLocation, + context: Option<&XcmContext>, + ) -> XcmResult { + log::trace!( + target: LOG_TARGET, + "deposit_asset what: {:?}, who: {:?}, context: {:?}", + what, + who, + context, + ); + // Check we handle this asset. + let instance = Matcher::matches_nonfungible(what).ok_or(MatchError::AssetNotHandled)?; + let who = AccountIdConverter::convert_location(who) + .ok_or(MatchError::AccountIdConversionFailed)?; + Asset::mint_into(&instance, &who).map_err(|e| XcmError::FailedToTransactAsset(e.into())) + } + + fn withdraw_asset( + what: &MultiAsset, + who: &MultiLocation, + maybe_context: Option<&XcmContext>, + ) -> result::Result { + log::trace!( + target: LOG_TARGET, + "withdraw_asset what: {:?}, who: {:?}, maybe_context: {:?}", + what, + who, + maybe_context, + ); + // Check we handle this asset. + let who = AccountIdConverter::convert_location(who) + .ok_or(MatchError::AccountIdConversionFailed)?; + let instance = Matcher::matches_nonfungible(what).ok_or(MatchError::AssetNotHandled)?; + Asset::burn(&instance, Some(&who)) + .map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; + Ok(what.clone().into()) + } +} + +pub struct NonFungibleAdapter( + PhantomData<(Asset, Matcher, AccountIdConverter, AccountId, CheckingAccount)>, +); +impl< + Asset: nonfungible::Mutate + nonfungible::Transfer, + Matcher: MatchesNonFungible, + AccountIdConverter: ConvertLocation, + AccountId: Clone + Eq, // can't get away without it since Currency is generic over it. + CheckingAccount: Get>, + > TransactAsset + for NonFungibleAdapter +{ + fn can_check_in(origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult { + NonFungibleMutateAdapter::< + Asset, + Matcher, + AccountIdConverter, + AccountId, + CheckingAccount, + >::can_check_in(origin, what, context) + } + + fn check_in(origin: &MultiLocation, what: &MultiAsset, context: &XcmContext) { + NonFungibleMutateAdapter::< + Asset, + Matcher, + AccountIdConverter, + AccountId, + CheckingAccount, + >::check_in(origin, what, context) + } + + fn can_check_out(dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) -> XcmResult { + NonFungibleMutateAdapter::< + Asset, + Matcher, + AccountIdConverter, + AccountId, + CheckingAccount, + >::can_check_out(dest, what, context) + } + + fn check_out(dest: &MultiLocation, what: &MultiAsset, context: &XcmContext) { + NonFungibleMutateAdapter::< + Asset, + Matcher, + AccountIdConverter, + AccountId, + CheckingAccount, + >::check_out(dest, what, context) + } + + fn deposit_asset( + what: &MultiAsset, + who: &MultiLocation, + context: Option<&XcmContext>, + ) -> XcmResult { + NonFungibleMutateAdapter::< + Asset, + Matcher, + AccountIdConverter, + AccountId, + CheckingAccount, + >::deposit_asset(what, who, context) + } + + fn withdraw_asset( + what: &MultiAsset, + who: &MultiLocation, + maybe_context: Option<&XcmContext>, + ) -> result::Result { + NonFungibleMutateAdapter::< + Asset, + Matcher, + AccountIdConverter, + AccountId, + CheckingAccount, + >::withdraw_asset(what, who, maybe_context) + } + + fn transfer_asset( + what: &MultiAsset, + from: &MultiLocation, + to: &MultiLocation, + context: &XcmContext, + ) -> result::Result { + NonFungibleTransferAdapter::::transfer_asset( + what, from, to, context, + ) + } +} diff --git a/runtime/regionx/src/lib.rs b/runtime/regionx/src/lib.rs index d70b59a1..e85bd39b 100644 --- a/runtime/regionx/src/lib.rs +++ b/runtime/regionx/src/lib.rs @@ -23,6 +23,11 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); extern crate alloc; + +// TODO remove: +mod adapter; +use adapter::NonFungibleAdapter; + mod weights; pub mod xcm_config; diff --git a/runtime/regionx/src/xcm_config.rs b/runtime/regionx/src/xcm_config.rs index a1c041cc..d8613c68 100644 --- a/runtime/regionx/src/xcm_config.rs +++ b/runtime/regionx/src/xcm_config.rs @@ -16,7 +16,7 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, Regions, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, - CORETIME_CHAIN_PARA_ID, + CORETIME_CHAIN_PARA_ID, NonFungibleAdapter, }; use frame_support::{ match_types, parameter_types, @@ -33,7 +33,7 @@ use xcm_builder::{ FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, NonFungibleAdapter, + TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::XcmExecutor; From fab2cc89c4f7ad4343acf364b86d73f7ba225466 Mon Sep 17 00:00:00 2001 From: Szegoo Date: Sat, 4 May 2024 17:03:32 +0200 Subject: [PATCH 03/29] fix merge --- runtime/regionx/src/adapter.rs | 4 ++-- runtime/regionx/src/lib.rs | 1 - runtime/regionx/src/xcm_config.rs | 8 ++++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/runtime/regionx/src/adapter.rs b/runtime/regionx/src/adapter.rs index 9d43078a..74e70732 100644 --- a/runtime/regionx/src/adapter.rs +++ b/runtime/regionx/src/adapter.rs @@ -1,5 +1,5 @@ // TODO: remove this file -// This has been temporarily added here because the NonFungibleAdapter is in release 1.7.0 +// This has been temporarily added here because the NonFungibleAdapter is in release 1.7.0 // or later, but we cannot update to that version now because of ISMP. // Copyright (C) Parity Technologies (UK) Ltd. @@ -20,13 +20,13 @@ //! Adapters to work with [`frame_support::traits::tokens::nonfungible`] through XCM. -use xcm_builder::MintLocation; use frame_support::{ ensure, traits::{tokens::nonfungible, Get}, }; use sp_std::{marker::PhantomData, prelude::*, result}; use xcm::latest::prelude::*; +use xcm_builder::MintLocation; use xcm_executor::traits::{ ConvertLocation, Error as MatchError, MatchesNonFungible, TransactAsset, }; diff --git a/runtime/regionx/src/lib.rs b/runtime/regionx/src/lib.rs index c6c92881..ba8db6f5 100644 --- a/runtime/regionx/src/lib.rs +++ b/runtime/regionx/src/lib.rs @@ -23,7 +23,6 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); extern crate alloc; - // TODO remove: mod adapter; use adapter::NonFungibleAdapter; diff --git a/runtime/regionx/src/xcm_config.rs b/runtime/regionx/src/xcm_config.rs index 4364ae4d..14b05859 100644 --- a/runtime/regionx/src/xcm_config.rs +++ b/runtime/regionx/src/xcm_config.rs @@ -14,9 +14,9 @@ // along with RegionX. If not, see . use super::{ - AccountId, AllPalletsWithSystem, AssetId, Balance, Balances, Currencies, ParachainInfo, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, UnknownTokens, - CORETIME_CHAIN_PARA_ID, NonFungibleAdapter, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, AssetId, Balance, Balances, Currencies, NonFungibleAdapter, + ParachainInfo, ParachainSystem, PolkadotXcm, Regions, Runtime, RuntimeCall, RuntimeEvent, + RuntimeOrigin, UnknownTokens, WeightToFee, XcmpQueue, CORETIME_CHAIN_PARA_ID, }; use frame_support::{ match_types, parameter_types, @@ -34,7 +34,7 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, - FrameTransactionalProcessor, NativeAsset, ParentIsPreset, RelayChainAsNative, + FrameTransactionalProcessor, IsConcrete, NativeAsset, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, From 16e45eb79af43658d356dc0955b1158c76e5ce87 Mon Sep 17 00:00:00 2001 From: Szegoo Date: Sat, 4 May 2024 17:22:59 +0200 Subject: [PATCH 04/29] init tests --- e2e_tests/region-transfer.js | 63 ++++++++++++++++++++++ zombienet_tests/0006-region-transfer.toml | 33 ++++++++++++ zombienet_tests/0006-region-transfer.zndsl | 10 ++++ 3 files changed, 106 insertions(+) create mode 100644 e2e_tests/region-transfer.js create mode 100644 zombienet_tests/0006-region-transfer.toml create mode 100644 zombienet_tests/0006-region-transfer.zndsl diff --git a/e2e_tests/region-transfer.js b/e2e_tests/region-transfer.js new file mode 100644 index 00000000..49466ddd --- /dev/null +++ b/e2e_tests/region-transfer.js @@ -0,0 +1,63 @@ +const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); +const { submitExtrinsic, setupRelayAsset } = require("./common"); + +async function run(nodeName, networkInfo, _jsArgs) { + const { wsUri: regionXUri } = networkInfo.nodesByName[nodeName]; + const { wsUri: rococoUri } = networkInfo.nodesByName["rococo-validator01"]; + const { wsUri: coretimeUri } = networkInfo.nodesByName["coretime-collator01"]; + + const rococoApi = await ApiPromise.create({ + provider: new WsProvider(rococoUri), + }); + const regionXApi = await ApiPromise.create({provider: new WsProvider(regionXUri)}); + + // account to submit tx + const keyring = new zombie.Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + + const setRelayXcmVersion = rococoApi.tx.xcmPallet.forceDefaultXcmVersion([3]); + await submitExtrinsic(alice, rococoApi.tx.sudo.sudo(setRelayXcmVersion), {}); + const setCoretimeXcmVersion = coretimeUri.tx.xcmPallet.forceDefaultXcmVersion([3]); + await submitExtrinsic(alice, coretimeUri.tx.sudo.sudo(setCoretimeXcmVersion), {}); + + await setupRelayAsset(regionXApi, alice); + + const receiverKeypair = new Keyring(); + receiverKeypair.addFromAddress(alice.address); + + const feeAssetItem = 0; + const weightLimit = "Unlimited"; + const reserveTransfer = rococoApi.tx.xcmPallet.limitedReserveTransferAssets( + { V3: { parents: 0, interior: { X1: { Parachain: 2000 } } } }, //dest + { + V3: { + parents: 0, + interior: { + X1: { + AccountId32: { + chain: "Any", + id: receiverKeypair.pairs[0].publicKey, + }, + }, + }, + }, + }, //beneficiary + { + V3: [ + { + id: { + Concrete: { parents: 0, interior: "Here" }, + }, + fun: { + Fungible: 10n ** 9n, + }, + }, + ], + }, //asset + feeAssetItem, + weightLimit, + ); + await submitExtrinsic(alice, reserveTransfer, {}); +} + +module.exports = { run }; diff --git a/zombienet_tests/0006-region-transfer.toml b/zombienet_tests/0006-region-transfer.toml new file mode 100644 index 00000000..c6810bd7 --- /dev/null +++ b/zombienet_tests/0006-region-transfer.toml @@ -0,0 +1,33 @@ +[settings] +timeout = 1000 + +[relaychain] +chain = "rococo-local" +command = "polkadot" + + [[relaychain.nodes]] + name = "rococo-validator01" + validator = true + + [[relaychain.nodes]] + name = "rococo-validator02" + validator = true + +[[parachains]] +id = 1005 +chain = "coretime-rococo-local" +addToGenesis = true + + [parachains.collator] + name = "coretime-collator01" + command = "polkadot-parachain" + args = [ "-lruntime=debug,parachain=trace" ] + +[[parachains]] +id = 2000 +addToGenesis = false + + [parachains.collator] + name = "regionx-collator01" + command = "regionx-node" + args = [ "-lruntime=debug,parachain=trace" ] diff --git a/zombienet_tests/0006-region-transfer.zndsl b/zombienet_tests/0006-region-transfer.zndsl new file mode 100644 index 00000000..b292dd12 --- /dev/null +++ b/zombienet_tests/0006-region-transfer.zndsl @@ -0,0 +1,10 @@ +Description: Native currency fee payment +Network: ./0006-region-transfer.toml +Creds: config + +rococo-validator01: is up +rococo-validator02: is up + +rococo-validator01: parachain 2000 is registered within 225 seconds + +regionx-collator01: js-script ../e2e_tests/region-transfer.js return is 0 within 400 seconds From 171773ad1b843a135a2a79946a41d298e95a4898 Mon Sep 17 00:00:00 2001 From: Sergej Date: Sat, 4 May 2024 20:05:18 +0200 Subject: [PATCH 05/29] progress --- e2e_tests/consts.js | 19 ++++++ e2e_tests/custom-fee-payment.js | 4 +- e2e_tests/package.json | 3 +- e2e_tests/region-transfer.js | 79 ++++++++++++++++++---- zombienet_tests/0006-region-transfer.toml | 2 +- zombienet_tests/0006-region-transfer.zndsl | 2 + 6 files changed, 89 insertions(+), 20 deletions(-) create mode 100644 e2e_tests/consts.js diff --git a/e2e_tests/consts.js b/e2e_tests/consts.js new file mode 100644 index 00000000..665f8fe9 --- /dev/null +++ b/e2e_tests/consts.js @@ -0,0 +1,19 @@ +const UNIT = 10 ** 12; // ROC has 12 decimals + +const INITIAL_PRICE = 50 * UNIT; +const CORE_COUNT = 10; +const TIMESLICE_PERIOD = 80; +const IDEAL_CORES_SOLD = 5; + +const CONFIG = { + advance_notice: 20, + interlude_length: 0, + leadin_length: 10, + ideal_bulk_proportion: 0, + limit_cores_offered: 50, + region_length: 30, + renewal_bump: 10, + contribution_timeout: 5, +}; + +module.exports = {UNIT, INITIAL_PRICE, CORE_COUNT, TIMESLICE_PERIOD, IDEAL_CORES_SOLD, CONFIG}; diff --git a/e2e_tests/custom-fee-payment.js b/e2e_tests/custom-fee-payment.js index ab0db92c..dd645b41 100644 --- a/e2e_tests/custom-fee-payment.js +++ b/e2e_tests/custom-fee-payment.js @@ -5,9 +5,7 @@ async function run(nodeName, networkInfo, _jsArgs) { const { wsUri: regionXUri } = networkInfo.nodesByName[nodeName]; const { wsUri: rococoUri } = networkInfo.nodesByName["rococo-validator01"]; - const rococoApi = await ApiPromise.create({ - provider: new WsProvider(rococoUri), - }); + const rococoApi = await ApiPromise.create({provider: new WsProvider(rococoUri)}); const regionXApi = await ApiPromise.create({ provider: new WsProvider(regionXUri), signedExtensions: { diff --git a/e2e_tests/package.json b/e2e_tests/package.json index 488bb14c..c922fae2 100644 --- a/e2e_tests/package.json +++ b/e2e_tests/package.json @@ -10,6 +10,7 @@ "author": "", "license": "ISC", "dependencies": { - "@polkadot/api": "^11.0.1" + "@polkadot/api": "^11.0.1", + "coretime-utils": "^0.2.8" } } diff --git a/e2e_tests/region-transfer.js b/e2e_tests/region-transfer.js index 49466ddd..4992356d 100644 --- a/e2e_tests/region-transfer.js +++ b/e2e_tests/region-transfer.js @@ -1,34 +1,38 @@ const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); -const { submitExtrinsic, setupRelayAsset } = require("./common"); +const { CONFIG, INITIAL_PRICE, UNIT, CORE_COUNT } = require("./consts"); +const { submitExtrinsic } = require("./common"); +const { CoreMask, Region, Id } = require("coretime-utils"); async function run(nodeName, networkInfo, _jsArgs) { const { wsUri: regionXUri } = networkInfo.nodesByName[nodeName]; - const { wsUri: rococoUri } = networkInfo.nodesByName["rococo-validator01"]; const { wsUri: coretimeUri } = networkInfo.nodesByName["coretime-collator01"]; - const rococoApi = await ApiPromise.create({ - provider: new WsProvider(rococoUri), - }); - const regionXApi = await ApiPromise.create({provider: new WsProvider(regionXUri)}); + const regionXApi = await ApiPromise.create({ provider: new WsProvider(regionXUri) }); + const coretimeApi = await ApiPromise.create({ provider: new WsProvider(coretimeUri), types: { Id } }); // account to submit tx const keyring = new zombie.Keyring({ type: "sr25519" }); const alice = keyring.addFromUri("//Alice"); - const setRelayXcmVersion = rococoApi.tx.xcmPallet.forceDefaultXcmVersion([3]); - await submitExtrinsic(alice, rococoApi.tx.sudo.sudo(setRelayXcmVersion), {}); - const setCoretimeXcmVersion = coretimeUri.tx.xcmPallet.forceDefaultXcmVersion([3]); - await submitExtrinsic(alice, coretimeUri.tx.sudo.sudo(setCoretimeXcmVersion), {}); + const setCoretimeXcmVersion = coretimeApi.tx.polkadotXcm.forceDefaultXcmVersion([3]); + await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setCoretimeXcmVersion), {}); - await setupRelayAsset(regionXApi, alice); + await configureBroker(coretimeApi, alice); + await startSales(coretimeApi, alice); + + const setBalanceCall = coretimeApi.tx.tokens.forceSetBalance(alice.address, 1000 * UNIT); + await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setBalanceCall), {}); + + const regionId = await purchaseRegion(coretimeApi, alice); + const encodedId = new Region(regionId, {end: 0, owner: '', paid: null}).getEncodedRegionId(coretimeApi); const receiverKeypair = new Keyring(); receiverKeypair.addFromAddress(alice.address); const feeAssetItem = 0; const weightLimit = "Unlimited"; - const reserveTransfer = rococoApi.tx.xcmPallet.limitedReserveTransferAssets( - { V3: { parents: 0, interior: { X1: { Parachain: 2000 } } } }, //dest + const reserveTransfer = coretimeApi.tx.polkadotXcm.limitedReserveTransferAssets( + { V3: { parents: 1, interior: { X1: { Parachain: 2000 } } } }, //dest { V3: { parents: 0, @@ -46,10 +50,15 @@ async function run(nodeName, networkInfo, _jsArgs) { V3: [ { id: { - Concrete: { parents: 0, interior: "Here" }, + Concrete: { + parents: 0, + interior: { X1: { PalletInstance: 50 } }, + }, }, fun: { - Fungible: 10n ** 9n, + NonFungible: { + Index: encodedId + } }, }, ], @@ -60,4 +69,44 @@ async function run(nodeName, networkInfo, _jsArgs) { await submitExtrinsic(alice, reserveTransfer, {}); } +async function configureBroker(coretimeApi, signer) { + const configCall = coretimeApi.tx.broker.configure(CONFIG); + const sudo = coretimeApi.tx.sudo.sudo(configCall) + return submitExtrinsic(signer, sudo, {}); +} + +async function startSales(coretimeApi, signer) { + const startSaleCall = coretimeApi.tx.broker.startSales(INITIAL_PRICE, CORE_COUNT); + const sudo = coretimeApi.tx.sudo.sudo(startSaleCall) + return submitExtrinsic(signer, sudo, {}); +} + +async function purchaseRegion(coretimeApi, buyer) { + const callTx = async (resolve) => { + const purchase = coretimeApi.tx.broker.purchase(INITIAL_PRICE * 2); + const unsub = await purchase.signAndSend(buyer, async (result) => { + if (result.status.isInBlock) { + const regionId = await getRegionId(coretimeApi); + unsub(); + resolve(regionId); + } + }); + }; + + return new Promise(callTx); +} + +async function getRegionId(coretimeApi) { + const events = await coretimeApi.query.system.events(); + + for (const record of events) { + const { event } = record; + if (event.section === "broker" && event.method === "Purchased") { + return event.data[1]; + } + } + + return { begin: 0, core: 0, mask: CoreMask.voidMask() }; +} + module.exports = { run }; diff --git a/zombienet_tests/0006-region-transfer.toml b/zombienet_tests/0006-region-transfer.toml index c6810bd7..037b2bdc 100644 --- a/zombienet_tests/0006-region-transfer.toml +++ b/zombienet_tests/0006-region-transfer.toml @@ -16,7 +16,7 @@ command = "polkadot" [[parachains]] id = 1005 chain = "coretime-rococo-local" -addToGenesis = true +addToGenesis = false [parachains.collator] name = "coretime-collator01" diff --git a/zombienet_tests/0006-region-transfer.zndsl b/zombienet_tests/0006-region-transfer.zndsl index b292dd12..f082bed0 100644 --- a/zombienet_tests/0006-region-transfer.zndsl +++ b/zombienet_tests/0006-region-transfer.zndsl @@ -8,3 +8,5 @@ rococo-validator02: is up rococo-validator01: parachain 2000 is registered within 225 seconds regionx-collator01: js-script ../e2e_tests/region-transfer.js return is 0 within 400 seconds + +sleep 1000 seconds From 48d8c48f428090839cd7933e588b8a0b7eec6f8a Mon Sep 17 00:00:00 2001 From: Szegoo Date: Sun, 5 May 2024 14:04:50 +0200 Subject: [PATCH 06/29] sending xcm works | receving fails --- e2e_tests/package.json | 2 +- e2e_tests/region-transfer.js | 38 ++++++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/e2e_tests/package.json b/e2e_tests/package.json index c922fae2..0719e269 100644 --- a/e2e_tests/package.json +++ b/e2e_tests/package.json @@ -11,6 +11,6 @@ "license": "ISC", "dependencies": { "@polkadot/api": "^11.0.1", - "coretime-utils": "^0.2.8" + "coretime-utils": "^0.3.0" } } diff --git a/e2e_tests/region-transfer.js b/e2e_tests/region-transfer.js index 4992356d..967ca16a 100644 --- a/e2e_tests/region-transfer.js +++ b/e2e_tests/region-transfer.js @@ -1,13 +1,15 @@ const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); const { CONFIG, INITIAL_PRICE, UNIT, CORE_COUNT } = require("./consts"); const { submitExtrinsic } = require("./common"); -const { CoreMask, Region, Id } = require("coretime-utils"); +const { CoreMask, getEncodedRegionId, Id } = require("coretime-utils"); async function run(nodeName, networkInfo, _jsArgs) { const { wsUri: regionXUri } = networkInfo.nodesByName[nodeName]; const { wsUri: coretimeUri } = networkInfo.nodesByName["coretime-collator01"]; + const { wsUri: rococoUri } = networkInfo.nodesByName["rococo-validator01"]; const regionXApi = await ApiPromise.create({ provider: new WsProvider(regionXUri) }); + const rococoApi = await ApiPromise.create({ provider: new WsProvider(rococoUri) }); const coretimeApi = await ApiPromise.create({ provider: new WsProvider(coretimeUri), types: { Id } }); // account to submit tx @@ -17,14 +19,18 @@ async function run(nodeName, networkInfo, _jsArgs) { const setCoretimeXcmVersion = coretimeApi.tx.polkadotXcm.forceDefaultXcmVersion([3]); await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setCoretimeXcmVersion), {}); + // TODO: open hrmp channel + await openHrmpChannel(alice, rococoApi, 1005, 2000); + await openHrmpChannel(alice, rococoApi, 2000, 1005); + await configureBroker(coretimeApi, alice); await startSales(coretimeApi, alice); - const setBalanceCall = coretimeApi.tx.tokens.forceSetBalance(alice.address, 1000 * UNIT); + const setBalanceCall = coretimeApi.tx.balances.forceSetBalance(alice.address, 1000 * UNIT); await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setBalanceCall), {}); const regionId = await purchaseRegion(coretimeApi, alice); - const encodedId = new Region(regionId, {end: 0, owner: '', paid: null}).getEncodedRegionId(coretimeApi); + const encodedId = getEncodedRegionId(regionId, coretimeApi); const receiverKeypair = new Keyring(); receiverKeypair.addFromAddress(alice.address); @@ -69,6 +75,29 @@ async function run(nodeName, networkInfo, _jsArgs) { await submitExtrinsic(alice, reserveTransfer, {}); } +async function openHrmpChannel(signer, relayApi, sender, recipient) { + const newHrmpChannel = [ + sender, + recipient, + 8, // Max capacity + 102400, // Max message size + ]; + + const openHrmp = relayApi.tx.parasSudoWrapper.sudoEstablishHrmpChannel(...newHrmpChannel); + const sudoCall = relayApi.tx.sudo.sudo(openHrmp); + + const callTx = async (resolve) => { + const unsub = await sudoCall.signAndSend(signer, (result) => { + if (result.status.isInBlock) { + unsub(); + resolve(); + } + }); + }; + + return new Promise(callTx); +} + async function configureBroker(coretimeApi, signer) { const configCall = coretimeApi.tx.broker.configure(CONFIG); const sudo = coretimeApi.tx.sudo.sudo(configCall) @@ -102,7 +131,8 @@ async function getRegionId(coretimeApi) { for (const record of events) { const { event } = record; if (event.section === "broker" && event.method === "Purchased") { - return event.data[1]; + const data = event.data[1].toHuman(); + return { begin: data.begin, core: data.core, mask: new CoreMask(data.mask) } } } From 919f7b422b295394967f0e4e00bf790aad560474 Mon Sep 17 00:00:00 2001 From: Sergej Date: Mon, 6 May 2024 13:26:10 +0200 Subject: [PATCH 07/29] cross-chain region transfer works --- e2e_tests/region-transfer.js | 3 +- runtime/primitives/src/lib.rs | 3 ++ runtime/regionx/src/xcm_config.rs | 50 +++++++++++++---------- zombienet_tests/0006-region-transfer.toml | 2 +- 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/e2e_tests/region-transfer.js b/e2e_tests/region-transfer.js index 967ca16a..b49cc35c 100644 --- a/e2e_tests/region-transfer.js +++ b/e2e_tests/region-transfer.js @@ -19,7 +19,6 @@ async function run(nodeName, networkInfo, _jsArgs) { const setCoretimeXcmVersion = coretimeApi.tx.polkadotXcm.forceDefaultXcmVersion([3]); await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setCoretimeXcmVersion), {}); - // TODO: open hrmp channel await openHrmpChannel(alice, rococoApi, 1005, 2000); await openHrmpChannel(alice, rococoApi, 2000, 1005); @@ -30,7 +29,7 @@ async function run(nodeName, networkInfo, _jsArgs) { await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setBalanceCall), {}); const regionId = await purchaseRegion(coretimeApi, alice); - const encodedId = getEncodedRegionId(regionId, coretimeApi); + const encodedId = getEncodedRegionId(regionId, coretimeApi).toString(); const receiverKeypair = new Keyring(); receiverKeypair.addFromAddress(alice.address); diff --git a/runtime/primitives/src/lib.rs b/runtime/primitives/src/lib.rs index fa80bbd0..c01da880 100644 --- a/runtime/primitives/src/lib.rs +++ b/runtime/primitives/src/lib.rs @@ -51,6 +51,9 @@ pub type Address = MultiAddress; /// Block header type as expected by this runtime. pub type Header = generic::Header; +/// u128 encoded `RegionId`. Used for specifying regions in XCM messages. +pub type RawRegionId = u128; + /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know /// the specifics of the runtime. They can then be made to be agnostic over specific formats /// of data like extrinsics, allowing for them to continue syncing the network through upgrades diff --git a/runtime/regionx/src/xcm_config.rs b/runtime/regionx/src/xcm_config.rs index 14b05859..4c6f5e7d 100644 --- a/runtime/regionx/src/xcm_config.rs +++ b/runtime/regionx/src/xcm_config.rs @@ -28,18 +28,21 @@ use orml_xcm_support::{DepositToAlternative, IsNativeConcrete, MultiCurrencyAdap use pallet_xcm::XcmPassthrough; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; -use regionx_primitives::assets::{REGX_ASSET_ID, RELAY_CHAIN_ASSET_ID}; +use regionx_primitives::{ + assets::{REGX_ASSET_ID, RELAY_CHAIN_ASSET_ID}, + RawRegionId, +}; use sp_runtime::traits::{AccountIdConversion, Convert}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, - FrameTransactionalProcessor, IsConcrete, NativeAsset, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WithComputedOrigin, WithUniqueTopic, + AllowUnpaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, + FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, NativeAsset, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, }; -use xcm_executor::XcmExecutor; +use xcm_executor::{traits::MatchesNonFungible, XcmExecutor}; parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); @@ -81,6 +84,21 @@ pub type FungiblesAssetTransactor = MultiCurrencyAdapter< DepositToAlternative, >; +pub type RegionTransactor = NonFungibleAdapter< + // Use this non-fungible implementation: + Regions, + // This adapter will handle coretime regions from the broker pallet. + IsConcrete, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We don't track any teleports. + (), +>; + +pub type AssetTransactors = (RegionTransactor, FungiblesAssetTransactor); + pub struct AssetIdConverter; impl Convert> for AssetIdConverter { fn convert(id: AssetId) -> Option { @@ -112,19 +130,6 @@ impl Convert> for AssetIdConverter { } } -pub type RegionTransactor = NonFungibleAdapter< - // Use this non-fungible implementation: - Regions, - // This adapter will handle coretime regions from the broker pallet. - IsConcrete, - // Convert an XCM Location into a local account id: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId, - // We don't track any teleports. - (), ->; - /// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, /// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can /// biases the kind of local `Origin` it will become. @@ -167,6 +172,7 @@ pub type Barrier = TrailingSetTopicAsId< TakeWeightCredit, WithComputedOrigin< ( + AllowUnpaidExecutionFrom, // <- TODO: remove AllowTopLevelPaidExecutionFrom, AllowExplicitUnpaidExecutionFrom, // ^^^ Parent and its exec plurality get free execution @@ -183,9 +189,9 @@ impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; // How to withdraw and deposit an asset. - type AssetTransactor = FungiblesAssetTransactor; + type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = NativeAsset; + type IsReserve = Everything; // TODO type IsTeleporter = (); // Teleporting is disabled. type UniversalLocation = UniversalLocation; type Barrier = Barrier; diff --git a/zombienet_tests/0006-region-transfer.toml b/zombienet_tests/0006-region-transfer.toml index 037b2bdc..9a7e2fe0 100644 --- a/zombienet_tests/0006-region-transfer.toml +++ b/zombienet_tests/0006-region-transfer.toml @@ -30,4 +30,4 @@ addToGenesis = false [parachains.collator] name = "regionx-collator01" command = "regionx-node" - args = [ "-lruntime=debug,parachain=trace" ] + args = [ "--log=xcm=trace,regions=trace" ] From 453c5dadcea34bdcf9490227c2c50a72ace05fac Mon Sep 17 00:00:00 2001 From: Sergej Date: Mon, 6 May 2024 15:49:21 +0200 Subject: [PATCH 08/29] regionx region receival test --- e2e_tests/common.js | 6 +++++- e2e_tests/region-transfer.js | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/e2e_tests/common.js b/e2e_tests/common.js index 60b7a576..e4b220f4 100644 --- a/e2e_tests/common.js +++ b/e2e_tests/common.js @@ -50,4 +50,8 @@ async function setupRelayAsset(api, signer) { await submitExtrinsic(signer, sudoCall, {}); } -module.exports = { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } +async function sleep(milliseconds) { + return new Promise(resolve => setTimeout(resolve, milliseconds)); +} + +module.exports = { submitExtrinsic, setupRelayAsset, sleep, RELAY_ASSET_ID } diff --git a/e2e_tests/region-transfer.js b/e2e_tests/region-transfer.js index b49cc35c..6cc0a820 100644 --- a/e2e_tests/region-transfer.js +++ b/e2e_tests/region-transfer.js @@ -1,10 +1,11 @@ const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); const { CONFIG, INITIAL_PRICE, UNIT, CORE_COUNT } = require("./consts"); -const { submitExtrinsic } = require("./common"); +const { submitExtrinsic, sleep } = require("./common"); const { CoreMask, getEncodedRegionId, Id } = require("coretime-utils"); +const assert = require('node:assert'); -async function run(nodeName, networkInfo, _jsArgs) { - const { wsUri: regionXUri } = networkInfo.nodesByName[nodeName]; +async function run(_nodeName, networkInfo, _jsArgs) { + const { wsUri: regionXUri } = networkInfo.nodesByName["regionx-collator01"]; const { wsUri: coretimeUri } = networkInfo.nodesByName["coretime-collator01"]; const { wsUri: rococoUri } = networkInfo.nodesByName["rococo-validator01"]; @@ -13,7 +14,7 @@ async function run(nodeName, networkInfo, _jsArgs) { const coretimeApi = await ApiPromise.create({ provider: new WsProvider(coretimeUri), types: { Id } }); // account to submit tx - const keyring = new zombie.Keyring({ type: "sr25519" }); + const keyring = new Keyring({ type: "sr25519" }); const alice = keyring.addFromUri("//Alice"); const setCoretimeXcmVersion = coretimeApi.tx.polkadotXcm.forceDefaultXcmVersion([3]); @@ -72,6 +73,13 @@ async function run(nodeName, networkInfo, _jsArgs) { weightLimit, ); await submitExtrinsic(alice, reserveTransfer, {}); + + await sleep(5000); + + const regions = (await regionXApi.query.regions.regions.entries()); + assert.equal(regions.length, 1); + assert.deepStrictEqual(regions[0][0].toHuman(), [{ begin: '34', core: '0', mask: "0xffffffffffffffffffff" }]); + assert.deepStrictEqual(regions[0][1].toHuman(), { owner: alice.address, record: 'Pending' }); } async function openHrmpChannel(signer, relayApi, sender, recipient) { From 4f5b133441d8ca7098ef62b99a8cd55d3c627d8e Mon Sep 17 00:00:00 2001 From: Sergej Date: Mon, 6 May 2024 17:12:57 +0200 Subject: [PATCH 09/29] switch to typescript --- .gitignore | 1 + e2e_tests/{common.js => common.ts} | 12 +- e2e_tests/{consts.js => consts.ts} | 2 +- e2e_tests/package.json | 6 +- ...{region-transfer.js => region-transfer.ts} | 39 +-- e2e_tests/tsconfig.json | 15 + zombienet_tests/0006-region-transfer.zndsl | 2 +- zombienet_tests/region-transfer.js | 314 ++++++++++++++++++ 8 files changed, 364 insertions(+), 27 deletions(-) rename e2e_tests/{common.js => common.ts} (74%) rename e2e_tests/{consts.js => consts.ts} (79%) rename e2e_tests/{region-transfer.js => region-transfer.ts} (78%) create mode 100644 e2e_tests/tsconfig.json create mode 100644 zombienet_tests/region-transfer.js diff --git a/.gitignore b/.gitignore index ca01b4c0..0576d96a 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ bin/ bin/ node_modules +build/ **/package-lock.json diff --git a/e2e_tests/common.js b/e2e_tests/common.ts similarity index 74% rename from e2e_tests/common.js rename to e2e_tests/common.ts index e4b220f4..f1511748 100644 --- a/e2e_tests/common.js +++ b/e2e_tests/common.ts @@ -1,6 +1,10 @@ +import { ApiPromise } from "@polkadot/api"; +import { SubmittableExtrinsic } from "@polkadot/api/types"; +import { KeyringPair } from "@polkadot/keyring/types"; + const RELAY_ASSET_ID = 1; -async function submitExtrinsic(signer, call, options) { +async function submitExtrinsic(signer: KeyringPair, call: SubmittableExtrinsic<"promise">, options: any): Promise { return new Promise(async (resolve, reject) => { const unsub = await call.signAndSend(signer, options, (result) => { console.log(`Current status is ${result.status}`); @@ -23,7 +27,7 @@ async function submitExtrinsic(signer, call, options) { }); } -async function setupRelayAsset(api, signer) { +async function setupRelayAsset(api: ApiPromise, signer: KeyringPair) { const assetMetadata = { decimals: 12, name: "ROC", @@ -50,8 +54,8 @@ async function setupRelayAsset(api, signer) { await submitExtrinsic(signer, sudoCall, {}); } -async function sleep(milliseconds) { +async function sleep(milliseconds: number) { return new Promise(resolve => setTimeout(resolve, milliseconds)); } -module.exports = { submitExtrinsic, setupRelayAsset, sleep, RELAY_ASSET_ID } +export { submitExtrinsic, setupRelayAsset, sleep, RELAY_ASSET_ID } diff --git a/e2e_tests/consts.js b/e2e_tests/consts.ts similarity index 79% rename from e2e_tests/consts.js rename to e2e_tests/consts.ts index 665f8fe9..3b2e0dff 100644 --- a/e2e_tests/consts.js +++ b/e2e_tests/consts.ts @@ -16,4 +16,4 @@ const CONFIG = { contribution_timeout: 5, }; -module.exports = {UNIT, INITIAL_PRICE, CORE_COUNT, TIMESLICE_PERIOD, IDEAL_CORES_SOLD, CONFIG}; +export {UNIT, INITIAL_PRICE, CORE_COUNT, TIMESLICE_PERIOD, IDEAL_CORES_SOLD, CONFIG}; diff --git a/e2e_tests/package.json b/e2e_tests/package.json index 0719e269..bcac170c 100644 --- a/e2e_tests/package.json +++ b/e2e_tests/package.json @@ -4,13 +4,15 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "npx tsc --outDir build > /dev/null" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@polkadot/api": "^11.0.1", - "coretime-utils": "^0.3.0" + "@polkadot/keyring": "^12.6.2", + "coretime-utils": "^0.3.0", + "typescript": "^5.4.5" } } diff --git a/e2e_tests/region-transfer.js b/e2e_tests/region-transfer.ts similarity index 78% rename from e2e_tests/region-transfer.js rename to e2e_tests/region-transfer.ts index 6cc0a820..e6b72bdf 100644 --- a/e2e_tests/region-transfer.js +++ b/e2e_tests/region-transfer.ts @@ -1,10 +1,11 @@ -const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); -const { CONFIG, INITIAL_PRICE, UNIT, CORE_COUNT } = require("./consts"); -const { submitExtrinsic, sleep } = require("./common"); -const { CoreMask, getEncodedRegionId, Id } = require("coretime-utils"); -const assert = require('node:assert'); - -async function run(_nodeName, networkInfo, _jsArgs) { +import { ApiPromise, WsProvider, Keyring } from "@polkadot/api"; +import { CONFIG, INITIAL_PRICE, UNIT, CORE_COUNT } from "./consts"; +import { submitExtrinsic, sleep } from "./common"; +import { KeyringPair } from "@polkadot/keyring/types"; +import { CoreMask, getEncodedRegionId, Id, RegionId } from "coretime-utils"; +import assert from 'node:assert'; + +async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { const { wsUri: regionXUri } = networkInfo.nodesByName["regionx-collator01"]; const { wsUri: coretimeUri } = networkInfo.nodesByName["coretime-collator01"]; const { wsUri: rococoUri } = networkInfo.nodesByName["rococo-validator01"]; @@ -82,10 +83,10 @@ async function run(_nodeName, networkInfo, _jsArgs) { assert.deepStrictEqual(regions[0][1].toHuman(), { owner: alice.address, record: 'Pending' }); } -async function openHrmpChannel(signer, relayApi, sender, recipient) { +async function openHrmpChannel(signer: KeyringPair, relayApi: ApiPromise, senderParaId: number, recipientParaId: number) { const newHrmpChannel = [ - sender, - recipient, + senderParaId, + recipientParaId, 8, // Max capacity 102400, // Max message size ]; @@ -93,7 +94,7 @@ async function openHrmpChannel(signer, relayApi, sender, recipient) { const openHrmp = relayApi.tx.parasSudoWrapper.sudoEstablishHrmpChannel(...newHrmpChannel); const sudoCall = relayApi.tx.sudo.sudo(openHrmp); - const callTx = async (resolve) => { + const callTx = async (resolve: any) => { const unsub = await sudoCall.signAndSend(signer, (result) => { if (result.status.isInBlock) { unsub(); @@ -105,22 +106,22 @@ async function openHrmpChannel(signer, relayApi, sender, recipient) { return new Promise(callTx); } -async function configureBroker(coretimeApi, signer) { +async function configureBroker(coretimeApi: ApiPromise, signer: KeyringPair): Promise { const configCall = coretimeApi.tx.broker.configure(CONFIG); const sudo = coretimeApi.tx.sudo.sudo(configCall) return submitExtrinsic(signer, sudo, {}); } -async function startSales(coretimeApi, signer) { +async function startSales(coretimeApi: ApiPromise, signer: KeyringPair): Promise { const startSaleCall = coretimeApi.tx.broker.startSales(INITIAL_PRICE, CORE_COUNT); const sudo = coretimeApi.tx.sudo.sudo(startSaleCall) return submitExtrinsic(signer, sudo, {}); } -async function purchaseRegion(coretimeApi, buyer) { - const callTx = async (resolve) => { +async function purchaseRegion(coretimeApi: ApiPromise, buyer: KeyringPair): Promise { + const callTx = async (resolve: (regionId: RegionId) => void) => { const purchase = coretimeApi.tx.broker.purchase(INITIAL_PRICE * 2); - const unsub = await purchase.signAndSend(buyer, async (result) => { + const unsub = await purchase.signAndSend(buyer, async (result: any) => { if (result.status.isInBlock) { const regionId = await getRegionId(coretimeApi); unsub(); @@ -132,8 +133,8 @@ async function purchaseRegion(coretimeApi, buyer) { return new Promise(callTx); } -async function getRegionId(coretimeApi) { - const events = await coretimeApi.query.system.events(); +async function getRegionId(coretimeApi: ApiPromise): Promise { + const events: any = await coretimeApi.query.system.events(); for (const record of events) { const { event } = record; @@ -146,4 +147,4 @@ async function getRegionId(coretimeApi) { return { begin: 0, core: 0, mask: CoreMask.voidMask() }; } -module.exports = { run }; +export { run }; diff --git a/e2e_tests/tsconfig.json b/e2e_tests/tsconfig.json new file mode 100644 index 00000000..c9901f8a --- /dev/null +++ b/e2e_tests/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "commonjs", + "outDir": "build", + "target": "ES2020", + "strict": true, + "esModuleInterop": true + }, + "include": [ + "**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/zombienet_tests/0006-region-transfer.zndsl b/zombienet_tests/0006-region-transfer.zndsl index f082bed0..ed04f21b 100644 --- a/zombienet_tests/0006-region-transfer.zndsl +++ b/zombienet_tests/0006-region-transfer.zndsl @@ -7,6 +7,6 @@ rococo-validator02: is up rococo-validator01: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/region-transfer.js return is 0 within 400 seconds +regionx-collator01: js-script ../e2e_tests/build/region-transfer.js return is 0 within 400 seconds sleep 1000 seconds diff --git a/zombienet_tests/region-transfer.js b/zombienet_tests/region-transfer.js new file mode 100644 index 00000000..c7f57674 --- /dev/null +++ b/zombienet_tests/region-transfer.js @@ -0,0 +1,314 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { + step(generator.next(value)); + } + catch (e) { + reject(e); + } } + function rejected(value) { try { + step(generator["throw"](value)); + } + catch (e) { + reject(e); + } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function () { if (t[0] & 1) + throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) + throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) + try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) + return t; + if (y = 0, t) + op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: + case 1: + t = op; + break; + case 4: + _.label++; + return { value: op[1], done: false }; + case 5: + _.label++; + y = op[1]; + op = [0]; + continue; + case 7: + op = _.ops.pop(); + _.trys.pop(); + continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { + _ = 0; + continue; + } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { + _.label = op[1]; + break; + } + if (op[0] === 6 && _.label < t[1]) { + _.label = t[1]; + t = op; + break; + } + if (t && _.label < t[2]) { + _.label = t[2]; + _.ops.push(op); + break; + } + if (t[2]) + _.ops.pop(); + _.trys.pop(); + continue; + } + op = body.call(thisArg, _); + } + catch (e) { + op = [6, e]; + y = 0; + } + finally { + f = t = 0; + } + if (op[0] & 5) + throw op[1]; + return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.run = void 0; +var api_1 = require("@polkadot/api"); +var consts_1 = require("./consts"); +var common_1 = require("./common"); +var coretime_utils_1 = require("coretime-utils"); +var node_assert_1 = require("node:assert"); +function run(_nodeName, networkInfo, _jsArgs) { + return __awaiter(this, void 0, void 0, function () { + var regionXUri, coretimeUri, rococoUri, regionXApi, rococoApi, coretimeApi, keyring, alice, setCoretimeXcmVersion, setBalanceCall, regionId, encodedId, receiverKeypair, feeAssetItem, weightLimit, reserveTransfer, regions; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + regionXUri = networkInfo.nodesByName["regionx-collator01"].wsUri; + coretimeUri = networkInfo.nodesByName["coretime-collator01"].wsUri; + rococoUri = networkInfo.nodesByName["rococo-validator01"].wsUri; + return [4 /*yield*/, api_1.ApiPromise.create({ provider: new api_1.WsProvider(regionXUri) })]; + case 1: + regionXApi = _a.sent(); + return [4 /*yield*/, api_1.ApiPromise.create({ provider: new api_1.WsProvider(rococoUri) })]; + case 2: + rococoApi = _a.sent(); + return [4 /*yield*/, api_1.ApiPromise.create({ provider: new api_1.WsProvider(coretimeUri), types: { Id: coretime_utils_1.Id } })]; + case 3: + coretimeApi = _a.sent(); + keyring = new api_1.Keyring({ type: "sr25519" }); + alice = keyring.addFromUri("//Alice"); + setCoretimeXcmVersion = coretimeApi.tx.polkadotXcm.forceDefaultXcmVersion([3]); + return [4 /*yield*/, (0, common_1.submitExtrinsic)(alice, coretimeApi.tx.sudo.sudo(setCoretimeXcmVersion), {})]; + case 4: + _a.sent(); + return [4 /*yield*/, openHrmpChannel(alice, rococoApi, 1005, 2000)]; + case 5: + _a.sent(); + return [4 /*yield*/, openHrmpChannel(alice, rococoApi, 2000, 1005)]; + case 6: + _a.sent(); + return [4 /*yield*/, configureBroker(coretimeApi, alice)]; + case 7: + _a.sent(); + return [4 /*yield*/, startSales(coretimeApi, alice)]; + case 8: + _a.sent(); + setBalanceCall = coretimeApi.tx.balances.forceSetBalance(alice.address, 1000 * consts_1.UNIT); + return [4 /*yield*/, (0, common_1.submitExtrinsic)(alice, coretimeApi.tx.sudo.sudo(setBalanceCall), {})]; + case 9: + _a.sent(); + return [4 /*yield*/, purchaseRegion(coretimeApi, alice)]; + case 10: + regionId = _a.sent(); + encodedId = (0, coretime_utils_1.getEncodedRegionId)(regionId, coretimeApi).toString(); + receiverKeypair = new api_1.Keyring(); + receiverKeypair.addFromAddress(alice.address); + feeAssetItem = 0; + weightLimit = "Unlimited"; + reserveTransfer = coretimeApi.tx.polkadotXcm.limitedReserveTransferAssets({ V3: { parents: 1, interior: { X1: { Parachain: 2000 } } } }, //dest + { + V3: { + parents: 0, + interior: { + X1: { + AccountId32: { + chain: "Any", + id: receiverKeypair.pairs[0].publicKey, + }, + }, + }, + }, + }, //beneficiary + { + V3: [ + { + id: { + Concrete: { + parents: 0, + interior: { X1: { PalletInstance: 50 } }, + }, + }, + fun: { + NonFungible: { + Index: encodedId + } + }, + }, + ], + }, //asset + feeAssetItem, weightLimit); + return [4 /*yield*/, (0, common_1.submitExtrinsic)(alice, reserveTransfer, {})]; + case 11: + _a.sent(); + return [4 /*yield*/, (0, common_1.sleep)(5000)]; + case 12: + _a.sent(); + return [4 /*yield*/, regionXApi.query.regions.regions.entries()]; + case 13: + regions = (_a.sent()); + node_assert_1.default.equal(regions.length, 1); + node_assert_1.default.deepStrictEqual(regions[0][0].toHuman(), [{ begin: '34', core: '0', mask: "0xffffffffffffffffffff" }]); + node_assert_1.default.deepStrictEqual(regions[0][1].toHuman(), { owner: alice.address, record: 'Pending' }); + return [2 /*return*/]; + } + }); + }); +} +exports.run = run; +function openHrmpChannel(signer, relayApi, senderParaId, recipientParaId) { + return __awaiter(this, void 0, void 0, function () { + var newHrmpChannel, openHrmp, sudoCall, callTx; + var _a; + var _this = this; + return __generator(this, function (_b) { + newHrmpChannel = [ + senderParaId, + recipientParaId, + 8, // Max capacity + 102400, // Max message size + ]; + openHrmp = (_a = relayApi.tx.parasSudoWrapper).sudoEstablishHrmpChannel.apply(_a, newHrmpChannel); + sudoCall = relayApi.tx.sudo.sudo(openHrmp); + callTx = function (resolve) { + return __awaiter(_this, void 0, void 0, function () { + var unsub; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, sudoCall.signAndSend(signer, function (result) { + if (result.status.isInBlock) { + unsub(); + resolve(); + } + })]; + case 1: + unsub = _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + return [2 /*return*/, new Promise(callTx)]; + }); + }); +} +function configureBroker(coretimeApi, signer) { + return __awaiter(this, void 0, void 0, function () { + var configCall, sudo; + return __generator(this, function (_a) { + configCall = coretimeApi.tx.broker.configure(consts_1.CONFIG); + sudo = coretimeApi.tx.sudo.sudo(configCall); + return [2 /*return*/, (0, common_1.submitExtrinsic)(signer, sudo, {})]; + }); + }); +} +function startSales(coretimeApi, signer) { + return __awaiter(this, void 0, void 0, function () { + var startSaleCall, sudo; + return __generator(this, function (_a) { + startSaleCall = coretimeApi.tx.broker.startSales(consts_1.INITIAL_PRICE, consts_1.CORE_COUNT); + sudo = coretimeApi.tx.sudo.sudo(startSaleCall); + return [2 /*return*/, (0, common_1.submitExtrinsic)(signer, sudo, {})]; + }); + }); +} +function purchaseRegion(coretimeApi, buyer) { + return __awaiter(this, void 0, void 0, function () { + var callTx; + var _this = this; + return __generator(this, function (_a) { + callTx = function (resolve) { + return __awaiter(_this, void 0, void 0, function () { + var purchase, unsub; + var _this = this; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + purchase = coretimeApi.tx.broker.purchase(consts_1.INITIAL_PRICE * 2); + return [4 /*yield*/, purchase.signAndSend(buyer, function (result) { + return __awaiter(_this, void 0, void 0, function () { + var regionId; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!result.status.isInBlock) + return [3 /*break*/, 2]; + return [4 /*yield*/, getRegionId(coretimeApi)]; + case 1: + regionId = _a.sent(); + unsub(); + resolve(regionId); + _a.label = 2; + case 2: return [2 /*return*/]; + } + }); + }); + })]; + case 1: + unsub = _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + return [2 /*return*/, new Promise(callTx)]; + }); + }); +} +function getRegionId(coretimeApi) { + return __awaiter(this, void 0, void 0, function () { + var events, _i, events_1, record, event_1, data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, coretimeApi.query.system.events()]; + case 1: + events = _a.sent(); + for (_i = 0, events_1 = events; _i < events_1.length; _i++) { + record = events_1[_i]; + event_1 = record.event; + if (event_1.section === "broker" && event_1.method === "Purchased") { + data = event_1.data[1].toHuman(); + return [2 /*return*/, { begin: data.begin, core: data.core, mask: new coretime_utils_1.CoreMask(data.mask) }]; + } + } + return [2 /*return*/, { begin: 0, core: 0, mask: coretime_utils_1.CoreMask.voidMask() }]; + } + }); + }); +} From e4c4b1eb33a2a2fc229a15df77811633b62842da Mon Sep 17 00:00:00 2001 From: cuteolaf Date: Mon, 6 May 2024 16:10:46 +0000 Subject: [PATCH 10/29] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cd0e92c5..6ddcfb8c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ 3. Get the polkadot binary: ```sh - zombienet-linux setup polkadot + zombienet-linux setup polkadot polkadot-parachain Please add the dir to your $PATH by running the command: export PATH=/home//RegionX-Node/:$PATH From 875cbd796d971aa8630d443272b586ec69e868aa Mon Sep 17 00:00:00 2001 From: cuteolaf Date: Mon, 6 May 2024 16:11:00 +0000 Subject: [PATCH 11/29] update package name --- e2e_tests/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e_tests/package.json b/e2e_tests/package.json index bcac170c..b60b1bde 100644 --- a/e2e_tests/package.json +++ b/e2e_tests/package.json @@ -1,5 +1,5 @@ { - "name": "test", + "name": "e2e-tests", "version": "1.0.0", "description": "", "main": "index.js", From fab91926661c23f06bfcc36e0b364345eb045f0c Mon Sep 17 00:00:00 2001 From: cuteolaf Date: Mon, 6 May 2024 16:11:08 +0000 Subject: [PATCH 12/29] remove unused file --- zombienet_tests/region-transfer.js | 314 ----------------------------- 1 file changed, 314 deletions(-) delete mode 100644 zombienet_tests/region-transfer.js diff --git a/zombienet_tests/region-transfer.js b/zombienet_tests/region-transfer.js deleted file mode 100644 index c7f57674..00000000 --- a/zombienet_tests/region-transfer.js +++ /dev/null @@ -1,314 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { - step(generator.next(value)); - } - catch (e) { - reject(e); - } } - function rejected(value) { try { - step(generator["throw"](value)); - } - catch (e) { - reject(e); - } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function () { if (t[0] & 1) - throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) - throw new TypeError("Generator is already executing."); - while (g && (g = 0, op[0] && (_ = 0)), _) - try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) - return t; - if (y = 0, t) - op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: - case 1: - t = op; - break; - case 4: - _.label++; - return { value: op[1], done: false }; - case 5: - _.label++; - y = op[1]; - op = [0]; - continue; - case 7: - op = _.ops.pop(); - _.trys.pop(); - continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { - _ = 0; - continue; - } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { - _.label = op[1]; - break; - } - if (op[0] === 6 && _.label < t[1]) { - _.label = t[1]; - t = op; - break; - } - if (t && _.label < t[2]) { - _.label = t[2]; - _.ops.push(op); - break; - } - if (t[2]) - _.ops.pop(); - _.trys.pop(); - continue; - } - op = body.call(thisArg, _); - } - catch (e) { - op = [6, e]; - y = 0; - } - finally { - f = t = 0; - } - if (op[0] & 5) - throw op[1]; - return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.run = void 0; -var api_1 = require("@polkadot/api"); -var consts_1 = require("./consts"); -var common_1 = require("./common"); -var coretime_utils_1 = require("coretime-utils"); -var node_assert_1 = require("node:assert"); -function run(_nodeName, networkInfo, _jsArgs) { - return __awaiter(this, void 0, void 0, function () { - var regionXUri, coretimeUri, rococoUri, regionXApi, rococoApi, coretimeApi, keyring, alice, setCoretimeXcmVersion, setBalanceCall, regionId, encodedId, receiverKeypair, feeAssetItem, weightLimit, reserveTransfer, regions; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - regionXUri = networkInfo.nodesByName["regionx-collator01"].wsUri; - coretimeUri = networkInfo.nodesByName["coretime-collator01"].wsUri; - rococoUri = networkInfo.nodesByName["rococo-validator01"].wsUri; - return [4 /*yield*/, api_1.ApiPromise.create({ provider: new api_1.WsProvider(regionXUri) })]; - case 1: - regionXApi = _a.sent(); - return [4 /*yield*/, api_1.ApiPromise.create({ provider: new api_1.WsProvider(rococoUri) })]; - case 2: - rococoApi = _a.sent(); - return [4 /*yield*/, api_1.ApiPromise.create({ provider: new api_1.WsProvider(coretimeUri), types: { Id: coretime_utils_1.Id } })]; - case 3: - coretimeApi = _a.sent(); - keyring = new api_1.Keyring({ type: "sr25519" }); - alice = keyring.addFromUri("//Alice"); - setCoretimeXcmVersion = coretimeApi.tx.polkadotXcm.forceDefaultXcmVersion([3]); - return [4 /*yield*/, (0, common_1.submitExtrinsic)(alice, coretimeApi.tx.sudo.sudo(setCoretimeXcmVersion), {})]; - case 4: - _a.sent(); - return [4 /*yield*/, openHrmpChannel(alice, rococoApi, 1005, 2000)]; - case 5: - _a.sent(); - return [4 /*yield*/, openHrmpChannel(alice, rococoApi, 2000, 1005)]; - case 6: - _a.sent(); - return [4 /*yield*/, configureBroker(coretimeApi, alice)]; - case 7: - _a.sent(); - return [4 /*yield*/, startSales(coretimeApi, alice)]; - case 8: - _a.sent(); - setBalanceCall = coretimeApi.tx.balances.forceSetBalance(alice.address, 1000 * consts_1.UNIT); - return [4 /*yield*/, (0, common_1.submitExtrinsic)(alice, coretimeApi.tx.sudo.sudo(setBalanceCall), {})]; - case 9: - _a.sent(); - return [4 /*yield*/, purchaseRegion(coretimeApi, alice)]; - case 10: - regionId = _a.sent(); - encodedId = (0, coretime_utils_1.getEncodedRegionId)(regionId, coretimeApi).toString(); - receiverKeypair = new api_1.Keyring(); - receiverKeypair.addFromAddress(alice.address); - feeAssetItem = 0; - weightLimit = "Unlimited"; - reserveTransfer = coretimeApi.tx.polkadotXcm.limitedReserveTransferAssets({ V3: { parents: 1, interior: { X1: { Parachain: 2000 } } } }, //dest - { - V3: { - parents: 0, - interior: { - X1: { - AccountId32: { - chain: "Any", - id: receiverKeypair.pairs[0].publicKey, - }, - }, - }, - }, - }, //beneficiary - { - V3: [ - { - id: { - Concrete: { - parents: 0, - interior: { X1: { PalletInstance: 50 } }, - }, - }, - fun: { - NonFungible: { - Index: encodedId - } - }, - }, - ], - }, //asset - feeAssetItem, weightLimit); - return [4 /*yield*/, (0, common_1.submitExtrinsic)(alice, reserveTransfer, {})]; - case 11: - _a.sent(); - return [4 /*yield*/, (0, common_1.sleep)(5000)]; - case 12: - _a.sent(); - return [4 /*yield*/, regionXApi.query.regions.regions.entries()]; - case 13: - regions = (_a.sent()); - node_assert_1.default.equal(regions.length, 1); - node_assert_1.default.deepStrictEqual(regions[0][0].toHuman(), [{ begin: '34', core: '0', mask: "0xffffffffffffffffffff" }]); - node_assert_1.default.deepStrictEqual(regions[0][1].toHuman(), { owner: alice.address, record: 'Pending' }); - return [2 /*return*/]; - } - }); - }); -} -exports.run = run; -function openHrmpChannel(signer, relayApi, senderParaId, recipientParaId) { - return __awaiter(this, void 0, void 0, function () { - var newHrmpChannel, openHrmp, sudoCall, callTx; - var _a; - var _this = this; - return __generator(this, function (_b) { - newHrmpChannel = [ - senderParaId, - recipientParaId, - 8, // Max capacity - 102400, // Max message size - ]; - openHrmp = (_a = relayApi.tx.parasSudoWrapper).sudoEstablishHrmpChannel.apply(_a, newHrmpChannel); - sudoCall = relayApi.tx.sudo.sudo(openHrmp); - callTx = function (resolve) { - return __awaiter(_this, void 0, void 0, function () { - var unsub; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, sudoCall.signAndSend(signer, function (result) { - if (result.status.isInBlock) { - unsub(); - resolve(); - } - })]; - case 1: - unsub = _a.sent(); - return [2 /*return*/]; - } - }); - }); - }; - return [2 /*return*/, new Promise(callTx)]; - }); - }); -} -function configureBroker(coretimeApi, signer) { - return __awaiter(this, void 0, void 0, function () { - var configCall, sudo; - return __generator(this, function (_a) { - configCall = coretimeApi.tx.broker.configure(consts_1.CONFIG); - sudo = coretimeApi.tx.sudo.sudo(configCall); - return [2 /*return*/, (0, common_1.submitExtrinsic)(signer, sudo, {})]; - }); - }); -} -function startSales(coretimeApi, signer) { - return __awaiter(this, void 0, void 0, function () { - var startSaleCall, sudo; - return __generator(this, function (_a) { - startSaleCall = coretimeApi.tx.broker.startSales(consts_1.INITIAL_PRICE, consts_1.CORE_COUNT); - sudo = coretimeApi.tx.sudo.sudo(startSaleCall); - return [2 /*return*/, (0, common_1.submitExtrinsic)(signer, sudo, {})]; - }); - }); -} -function purchaseRegion(coretimeApi, buyer) { - return __awaiter(this, void 0, void 0, function () { - var callTx; - var _this = this; - return __generator(this, function (_a) { - callTx = function (resolve) { - return __awaiter(_this, void 0, void 0, function () { - var purchase, unsub; - var _this = this; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - purchase = coretimeApi.tx.broker.purchase(consts_1.INITIAL_PRICE * 2); - return [4 /*yield*/, purchase.signAndSend(buyer, function (result) { - return __awaiter(_this, void 0, void 0, function () { - var regionId; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (!result.status.isInBlock) - return [3 /*break*/, 2]; - return [4 /*yield*/, getRegionId(coretimeApi)]; - case 1: - regionId = _a.sent(); - unsub(); - resolve(regionId); - _a.label = 2; - case 2: return [2 /*return*/]; - } - }); - }); - })]; - case 1: - unsub = _a.sent(); - return [2 /*return*/]; - } - }); - }); - }; - return [2 /*return*/, new Promise(callTx)]; - }); - }); -} -function getRegionId(coretimeApi) { - return __awaiter(this, void 0, void 0, function () { - var events, _i, events_1, record, event_1, data; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, coretimeApi.query.system.events()]; - case 1: - events = _a.sent(); - for (_i = 0, events_1 = events; _i < events_1.length; _i++) { - record = events_1[_i]; - event_1 = record.event; - if (event_1.section === "broker" && event_1.method === "Purchased") { - data = event_1.data[1].toHuman(); - return [2 /*return*/, { begin: data.begin, core: data.core, mask: new coretime_utils_1.CoreMask(data.mask) }]; - } - } - return [2 /*return*/, { begin: 0, core: 0, mask: coretime_utils_1.CoreMask.voidMask() }]; - } - }); - }); -} From 7f1889e89ccc87638a7cbd58637375c59f9ff04d Mon Sep 17 00:00:00 2001 From: cuteolaf Date: Mon, 6 May 2024 16:17:16 +0000 Subject: [PATCH 13/29] remove unused imports --- runtime/regionx/src/xcm_config.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/runtime/regionx/src/xcm_config.rs b/runtime/regionx/src/xcm_config.rs index 4c6f5e7d..72b43569 100644 --- a/runtime/regionx/src/xcm_config.rs +++ b/runtime/regionx/src/xcm_config.rs @@ -28,21 +28,18 @@ use orml_xcm_support::{DepositToAlternative, IsNativeConcrete, MultiCurrencyAdap use pallet_xcm::XcmPassthrough; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; -use regionx_primitives::{ - assets::{REGX_ASSET_ID, RELAY_CHAIN_ASSET_ID}, - RawRegionId, -}; +use regionx_primitives::assets::{REGX_ASSET_ID, RELAY_CHAIN_ASSET_ID}; use sp_runtime::traits::{AccountIdConversion, Convert}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, - FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, NativeAsset, ParentIsPreset, + FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, }; -use xcm_executor::{traits::MatchesNonFungible, XcmExecutor}; +use xcm_executor::XcmExecutor; parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); From 498a77ba9fcd75e7eb8af8dcbdfbb51a82abc915 Mon Sep 17 00:00:00 2001 From: cuteolaf Date: Mon, 6 May 2024 16:27:27 +0000 Subject: [PATCH 14/29] cargo fmt --- runtime/regionx/src/xcm_config.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime/regionx/src/xcm_config.rs b/runtime/regionx/src/xcm_config.rs index 72b43569..38084d35 100644 --- a/runtime/regionx/src/xcm_config.rs +++ b/runtime/regionx/src/xcm_config.rs @@ -34,10 +34,10 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, - FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, + FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, ParentIsPreset, RelayChainAsNative, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::XcmExecutor; From ae57546a02667ce2333b340311a38cc8a6a384f9 Mon Sep 17 00:00:00 2001 From: Sergej Date: Tue, 7 May 2024 08:53:39 +0200 Subject: [PATCH 15/29] move region-transfer test --- .../index.ts} | 45 +++++++++++++++++-- zombienet_tests/0006-region-transfer.zndsl | 2 +- 2 files changed, 42 insertions(+), 5 deletions(-) rename e2e_tests/{region-transfer.ts => region-transfer/index.ts} (81%) diff --git a/e2e_tests/region-transfer.ts b/e2e_tests/region-transfer/index.ts similarity index 81% rename from e2e_tests/region-transfer.ts rename to e2e_tests/region-transfer/index.ts index e6b72bdf..487381c3 100644 --- a/e2e_tests/region-transfer.ts +++ b/e2e_tests/region-transfer/index.ts @@ -1,6 +1,6 @@ import { ApiPromise, WsProvider, Keyring } from "@polkadot/api"; -import { CONFIG, INITIAL_PRICE, UNIT, CORE_COUNT } from "./consts"; -import { submitExtrinsic, sleep } from "./common"; +import { CONFIG, INITIAL_PRICE, UNIT, CORE_COUNT } from "../consts"; +import { submitExtrinsic, sleep } from "../common"; import { KeyringPair } from "@polkadot/keyring/types"; import { CoreMask, getEncodedRegionId, Id, RegionId } from "coretime-utils"; import assert from 'node:assert'; @@ -38,7 +38,7 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { const feeAssetItem = 0; const weightLimit = "Unlimited"; - const reserveTransfer = coretimeApi.tx.polkadotXcm.limitedReserveTransferAssets( + const reserveTransferToRegionX = coretimeApi.tx.polkadotXcm.limitedReserveTransferAssets( { V3: { parents: 1, interior: { X1: { Parachain: 2000 } } } }, //dest { V3: { @@ -73,7 +73,7 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { feeAssetItem, weightLimit, ); - await submitExtrinsic(alice, reserveTransfer, {}); + await submitExtrinsic(alice, reserveTransferToRegionX, {}); await sleep(5000); @@ -81,6 +81,43 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { assert.equal(regions.length, 1); assert.deepStrictEqual(regions[0][0].toHuman(), [{ begin: '34', core: '0', mask: "0xffffffffffffffffffff" }]); assert.deepStrictEqual(regions[0][1].toHuman(), { owner: alice.address, record: 'Pending' }); + + const reserveTransferToCoretime = coretimeApi.tx.polkadotXcm.limitedReserveTransferAssets( + { V3: { parents: 1, interior: { X1: { Parachain: 1005 } } } }, //dest + { + V3: { + parents: 0, + interior: { + X1: { + AccountId32: { + chain: "Any", + id: receiverKeypair.pairs[0].publicKey, + }, + }, + }, + }, + }, //beneficiary + { + V3: [ + { + id: { + Concrete: { + parents: 1, + interior: { X2: [ {Parachain: 2000}, { PalletInstance: 50 }] }, + }, + }, + fun: { + NonFungible: { + Index: encodedId + } + }, + }, + ], + }, //asset + feeAssetItem, + weightLimit, + ); + await submitExtrinsic(alice, reserveTransferToCoretime, {}); } async function openHrmpChannel(signer: KeyringPair, relayApi: ApiPromise, senderParaId: number, recipientParaId: number) { diff --git a/zombienet_tests/0006-region-transfer.zndsl b/zombienet_tests/0006-region-transfer.zndsl index ed04f21b..11227d16 100644 --- a/zombienet_tests/0006-region-transfer.zndsl +++ b/zombienet_tests/0006-region-transfer.zndsl @@ -7,6 +7,6 @@ rococo-validator02: is up rococo-validator01: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/build/region-transfer.js return is 0 within 400 seconds +regionx-collator01: js-script ../e2e_tests/build/region-transfer/index.js return is 0 within 400 seconds sleep 1000 seconds From 17abd972fea478c9c1ce50144c7a93f20c9658e1 Mon Sep 17 00:00:00 2001 From: Sergej Date: Tue, 7 May 2024 11:51:42 +0200 Subject: [PATCH 16/29] transfering to coretime chain --- e2e_tests/package.json | 5 ++++- e2e_tests/region-transfer/index.ts | 17 ++++++++--------- e2e_tests/test.js | 10 ++++++++++ runtime/regionx/src/xcm_config.rs | 2 +- zombienet_tests/0006-region-transfer.toml | 2 +- 5 files changed, 24 insertions(+), 12 deletions(-) create mode 100644 e2e_tests/test.js diff --git a/e2e_tests/package.json b/e2e_tests/package.json index b60b1bde..db9d4c4e 100644 --- a/e2e_tests/package.json +++ b/e2e_tests/package.json @@ -4,7 +4,10 @@ "description": "", "main": "index.js", "scripts": { - "build": "npx tsc --outDir build > /dev/null" + "build": "npx tsc --outDir build > /dev/null", + "test:block-production": "zombienet-linux -p native test ./zombienet_tests/0001-block-production.zndsl", + "test:native-fee-payment": "zombienet-linux -p native test ./zombienet_tests/0002-block-production.zndsl", + "test:custom-fee-payment": "zombienet-linux -p native test ./zombienet_tests/0001-block-production.zndsl" }, "keywords": [], "author": "", diff --git a/e2e_tests/region-transfer/index.ts b/e2e_tests/region-transfer/index.ts index 487381c3..ef48202a 100644 --- a/e2e_tests/region-transfer/index.ts +++ b/e2e_tests/region-transfer/index.ts @@ -11,7 +11,7 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { const { wsUri: rococoUri } = networkInfo.nodesByName["rococo-validator01"]; const regionXApi = await ApiPromise.create({ provider: new WsProvider(regionXUri) }); - const rococoApi = await ApiPromise.create({ provider: new WsProvider(rococoUri) }); + const rococoApi = await ApiPromise.create({ provider: new WsProvider(rococoUri), types: { Id } }); const coretimeApi = await ApiPromise.create({ provider: new WsProvider(coretimeUri), types: { Id } }); // account to submit tx @@ -31,7 +31,6 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setBalanceCall), {}); const regionId = await purchaseRegion(coretimeApi, alice); - const encodedId = getEncodedRegionId(regionId, coretimeApi).toString(); const receiverKeypair = new Keyring(); receiverKeypair.addFromAddress(alice.address); @@ -64,7 +63,7 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { }, fun: { NonFungible: { - Index: encodedId + Index: getEncodedRegionId(regionId, coretimeApi).toString() } }, }, @@ -82,8 +81,8 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { assert.deepStrictEqual(regions[0][0].toHuman(), [{ begin: '34', core: '0', mask: "0xffffffffffffffffffff" }]); assert.deepStrictEqual(regions[0][1].toHuman(), { owner: alice.address, record: 'Pending' }); - const reserveTransferToCoretime = coretimeApi.tx.polkadotXcm.limitedReserveTransferAssets( - { V3: { parents: 1, interior: { X1: { Parachain: 1005 } } } }, //dest + const reserveTransferToCoretime = regionXApi.tx.polkadotXcm.limitedReserveTransferAssets( + { V3: { parents: 1, interior: { X1: { Parachain: 1005 } } } }, // dest { V3: { parents: 0, @@ -96,24 +95,24 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { }, }, }, - }, //beneficiary + }, // ^^ beneficiary { V3: [ { id: { Concrete: { parents: 1, - interior: { X2: [ {Parachain: 2000}, { PalletInstance: 50 }] }, + interior: { X2: [ {Parachain: 1005}, { PalletInstance: 50 }] }, }, }, fun: { NonFungible: { - Index: encodedId + Index: getEncodedRegionId(regionId, regionXApi).toString() } }, }, ], - }, //asset + }, // ^^ asset feeAssetItem, weightLimit, ); diff --git a/e2e_tests/test.js b/e2e_tests/test.js new file mode 100644 index 00000000..ec9db50d --- /dev/null +++ b/e2e_tests/test.js @@ -0,0 +1,10 @@ +const { ApiPromise, WsProvider } = require("@polkadot/api"); +const {Id, getEncodedRegionId, CoreMask} = require("coretime-utils"); + +const run = async() => { + const regionXApi = await ApiPromise.create({ provider: new WsProvider("ws://127.0.0.1:33247"), types: {Id} }); + + console.log(getEncodedRegionId({begin: 34, core: 0, mask: new CoreMask("0xffffffffffffffffffff")}, regionXApi).toString()); +} + +run(); \ No newline at end of file diff --git a/runtime/regionx/src/xcm_config.rs b/runtime/regionx/src/xcm_config.rs index 38084d35..58728bee 100644 --- a/runtime/regionx/src/xcm_config.rs +++ b/runtime/regionx/src/xcm_config.rs @@ -234,7 +234,7 @@ impl pallet_xcm::Config for Runtime { // Needs to be `Everything` for local testing. type XcmExecutor = XcmExecutor; type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Nothing; + type XcmReserveTransferFilter = Everything; type Weigher = FixedWeightBounds; type UniversalLocation = UniversalLocation; type RuntimeOrigin = RuntimeOrigin; diff --git a/zombienet_tests/0006-region-transfer.toml b/zombienet_tests/0006-region-transfer.toml index 9a7e2fe0..14f1d0b0 100644 --- a/zombienet_tests/0006-region-transfer.toml +++ b/zombienet_tests/0006-region-transfer.toml @@ -21,7 +21,7 @@ addToGenesis = false [parachains.collator] name = "coretime-collator01" command = "polkadot-parachain" - args = [ "-lruntime=debug,parachain=trace" ] + args = [ "--log=xcm=trace" ] [[parachains]] id = 2000 From 94c56ea81343eeed2fdc9a4c329e3cc79db9a327 Mon Sep 17 00:00:00 2001 From: Sergej Date: Tue, 7 May 2024 12:20:05 +0200 Subject: [PATCH 17/29] progress --- e2e_tests/common.ts | 43 ++++++++++++++++++++++++++++-- e2e_tests/package.json | 5 +--- e2e_tests/region-transfer/index.ts | 16 ++++++++++- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/e2e_tests/common.ts b/e2e_tests/common.ts index ef801d9e..e8e81b87 100644 --- a/e2e_tests/common.ts +++ b/e2e_tests/common.ts @@ -1,4 +1,4 @@ -import { ApiPromise } from "@polkadot/api"; +import { ApiPromise, Keyring } from "@polkadot/api"; import { SubmittableExtrinsic } from "@polkadot/api/types"; import { KeyringPair } from "@polkadot/keyring/types"; @@ -54,8 +54,47 @@ async function setupRelayAsset(api: ApiPromise, signer: KeyringPair) { await submitExtrinsic(signer, sudoCall, {}); } +async function transferRelayAssetToRegionX(amount: string, relayApi: ApiPromise, signer: KeyringPair) { + const receiverKeypair = new Keyring(); + receiverKeypair.addFromAddress(signer.address); + + const feeAssetItem = 0; + const weightLimit = "Unlimited"; + const reserveTransfer = relayApi.tx.xcmPallet.limitedReserveTransferAssets( + { V3: { parents: 0, interior: { X1: { Parachain: 2000 } } } }, //dest + { + V3: { + parents: 0, + interior: { + X1: { + AccountId32: { + chain: "Any", + id: receiverKeypair.pairs[0].publicKey, + }, + }, + }, + }, + }, //beneficiary + { + V3: [ + { + id: { + Concrete: { parents: 0, interior: "Here" }, + }, + fun: { + Fungible: amount, + }, + }, + ], + }, //asset + feeAssetItem, + weightLimit, + ); + await submitExtrinsic(signer, reserveTransfer, {}); +} + async function sleep(milliseconds: number) { return new Promise(resolve => setTimeout(resolve, milliseconds)); } -export { submitExtrinsic, setupRelayAsset, sleep, RELAY_ASSET_ID } +export { submitExtrinsic, setupRelayAsset, transferRelayAssetToRegionX, sleep, RELAY_ASSET_ID } diff --git a/e2e_tests/package.json b/e2e_tests/package.json index db9d4c4e..b60b1bde 100644 --- a/e2e_tests/package.json +++ b/e2e_tests/package.json @@ -4,10 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "build": "npx tsc --outDir build > /dev/null", - "test:block-production": "zombienet-linux -p native test ./zombienet_tests/0001-block-production.zndsl", - "test:native-fee-payment": "zombienet-linux -p native test ./zombienet_tests/0002-block-production.zndsl", - "test:custom-fee-payment": "zombienet-linux -p native test ./zombienet_tests/0001-block-production.zndsl" + "build": "npx tsc --outDir build > /dev/null" }, "keywords": [], "author": "", diff --git a/e2e_tests/region-transfer/index.ts b/e2e_tests/region-transfer/index.ts index ef48202a..7c5d6766 100644 --- a/e2e_tests/region-transfer/index.ts +++ b/e2e_tests/region-transfer/index.ts @@ -1,6 +1,6 @@ import { ApiPromise, WsProvider, Keyring } from "@polkadot/api"; import { CONFIG, INITIAL_PRICE, UNIT, CORE_COUNT } from "../consts"; -import { submitExtrinsic, sleep } from "../common"; +import { submitExtrinsic, sleep, transferRelayAssetToRegionX, setupRelayAsset } from "../common"; import { KeyringPair } from "@polkadot/keyring/types"; import { CoreMask, getEncodedRegionId, Id, RegionId } from "coretime-utils"; import assert from 'node:assert'; @@ -24,6 +24,8 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { await openHrmpChannel(alice, rococoApi, 1005, 2000); await openHrmpChannel(alice, rococoApi, 2000, 1005); + await setupRelayAsset(regionXApi, alice); + await configureBroker(coretimeApi, alice); await startSales(coretimeApi, alice); @@ -74,6 +76,7 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { ); await submitExtrinsic(alice, reserveTransferToRegionX, {}); + await transferRelayAssetToRegionX((10n**12n).toString(), rococoApi, alice); await sleep(5000); const regions = (await regionXApi.query.regions.regions.entries()); @@ -98,6 +101,17 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { }, // ^^ beneficiary { V3: [ + { + id: { + Concrete: { + parents: 1, + interior: "Here", + }, + }, + fun: { + Fungible: 10n**10n + }, + }, { id: { Concrete: { From 7c35a498361647691355c1ff8d9cb1312e208b8f Mon Sep 17 00:00:00 2001 From: Szegoo Date: Tue, 7 May 2024 16:48:44 +0200 Subject: [PATCH 18/29] all good but unpaid execution? --- e2e_tests/package.json | 2 +- e2e_tests/region-transfer/index.ts | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/e2e_tests/package.json b/e2e_tests/package.json index d80e8490..d8878058 100644 --- a/e2e_tests/package.json +++ b/e2e_tests/package.json @@ -12,7 +12,7 @@ "dependencies": { "@polkadot/api": "^11.0.2", "@polkadot/keyring": "^12.6.2", - "coretime-utils": "^0.3.0", + "coretime-utils": "^0.3.2", "typescript": "^5.4.5" } } diff --git a/e2e_tests/region-transfer/index.ts b/e2e_tests/region-transfer/index.ts index 7c5d6766..9f6df1a7 100644 --- a/e2e_tests/region-transfer/index.ts +++ b/e2e_tests/region-transfer/index.ts @@ -2,7 +2,7 @@ import { ApiPromise, WsProvider, Keyring } from "@polkadot/api"; import { CONFIG, INITIAL_PRICE, UNIT, CORE_COUNT } from "../consts"; import { submitExtrinsic, sleep, transferRelayAssetToRegionX, setupRelayAsset } from "../common"; import { KeyringPair } from "@polkadot/keyring/types"; -import { CoreMask, getEncodedRegionId, Id, RegionId } from "coretime-utils"; +import { getEncodedRegionId, Id, RegionId, voidMask } from "coretime-utils"; import assert from 'node:assert'; async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { @@ -33,6 +33,7 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setBalanceCall), {}); const regionId = await purchaseRegion(coretimeApi, alice); + if(!regionId) throw new Error("RegionId not found"); const receiverKeypair = new Keyring(); receiverKeypair.addFromAddress(alice.address); @@ -81,7 +82,7 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { const regions = (await regionXApi.query.regions.regions.entries()); assert.equal(regions.length, 1); - assert.deepStrictEqual(regions[0][0].toHuman(), [{ begin: '34', core: '0', mask: "0xffffffffffffffffffff" }]); + assert.deepStrictEqual(regions[0][0].toHuman(), [regionId]); assert.deepStrictEqual(regions[0][1].toHuman(), { owner: alice.address, record: 'Pending' }); const reserveTransferToCoretime = regionXApi.tx.polkadotXcm.limitedReserveTransferAssets( @@ -168,8 +169,8 @@ async function startSales(coretimeApi: ApiPromise, signer: KeyringPair): Promise return submitExtrinsic(signer, sudo, {}); } -async function purchaseRegion(coretimeApi: ApiPromise, buyer: KeyringPair): Promise { - const callTx = async (resolve: (regionId: RegionId) => void) => { +async function purchaseRegion(coretimeApi: ApiPromise, buyer: KeyringPair): Promise { + const callTx = async (resolve: (regionId: RegionId | null) => void) => { const purchase = coretimeApi.tx.broker.purchase(INITIAL_PRICE * 2); const unsub = await purchase.signAndSend(buyer, async (result: any) => { if (result.status.isInBlock) { @@ -183,18 +184,18 @@ async function purchaseRegion(coretimeApi: ApiPromise, buyer: KeyringPair): Prom return new Promise(callTx); } -async function getRegionId(coretimeApi: ApiPromise): Promise { +async function getRegionId(coretimeApi: ApiPromise): Promise { const events: any = await coretimeApi.query.system.events(); for (const record of events) { const { event } = record; if (event.section === "broker" && event.method === "Purchased") { const data = event.data[1].toHuman(); - return { begin: data.begin, core: data.core, mask: new CoreMask(data.mask) } + return data; } } - return { begin: 0, core: 0, mask: CoreMask.voidMask() }; + return null; } export { run }; From e8c6d92770cab9bda01b661fc676ac2554a6e494 Mon Sep 17 00:00:00 2001 From: Sergej Date: Tue, 7 May 2024 20:21:02 +0200 Subject: [PATCH 19/29] works :)) but messy --- e2e_tests/region-transfer/index.ts | 11 +++++++++-- zombienet_tests/0006-region-transfer.zndsl | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/e2e_tests/region-transfer/index.ts b/e2e_tests/region-transfer/index.ts index 9f6df1a7..33ee23e7 100644 --- a/e2e_tests/region-transfer/index.ts +++ b/e2e_tests/region-transfer/index.ts @@ -2,9 +2,11 @@ import { ApiPromise, WsProvider, Keyring } from "@polkadot/api"; import { CONFIG, INITIAL_PRICE, UNIT, CORE_COUNT } from "../consts"; import { submitExtrinsic, sleep, transferRelayAssetToRegionX, setupRelayAsset } from "../common"; import { KeyringPair } from "@polkadot/keyring/types"; -import { getEncodedRegionId, Id, RegionId, voidMask } from "coretime-utils"; +import { getEncodedRegionId, Id, RegionId } from "coretime-utils"; import assert from 'node:assert'; +const PARA_SOVEREIGN_ACCOUNT = "5Eg2fntJ27qsari4FGrGhrMqKFDRnkNSR6UshkZYBGXmSuC8"; + async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { const { wsUri: regionXUri } = networkInfo.nodesByName["regionx-collator01"]; const { wsUri: coretimeUri } = networkInfo.nodesByName["coretime-collator01"]; @@ -19,7 +21,9 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { const alice = keyring.addFromUri("//Alice"); const setCoretimeXcmVersion = coretimeApi.tx.polkadotXcm.forceDefaultXcmVersion([3]); + const setRelayXcmVersion = rococoApi.tx.xcmPallet.forceDefaultXcmVersion([3]); await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setCoretimeXcmVersion), {}); + await submitExtrinsic(alice, rococoApi.tx.sudo.sudo(setRelayXcmVersion), {}); await openHrmpChannel(alice, rococoApi, 1005, 2000); await openHrmpChannel(alice, rococoApi, 2000, 1005); @@ -29,6 +33,8 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { await configureBroker(coretimeApi, alice); await startSales(coretimeApi, alice); + await sleep(2000); + const setBalanceCall = coretimeApi.tx.balances.forceSetBalance(alice.address, 1000 * UNIT); await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setBalanceCall), {}); @@ -78,7 +84,8 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { await submitExtrinsic(alice, reserveTransferToRegionX, {}); await transferRelayAssetToRegionX((10n**12n).toString(), rococoApi, alice); - await sleep(5000); + const fundSovereignAccount = coretimeApi.tx.balances.forceSetBalance(PARA_SOVEREIGN_ACCOUNT, 1000 * UNIT); + await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(fundSovereignAccount), {}); const regions = (await regionXApi.query.regions.regions.entries()); assert.equal(regions.length, 1); diff --git a/zombienet_tests/0006-region-transfer.zndsl b/zombienet_tests/0006-region-transfer.zndsl index 11227d16..4c745193 100644 --- a/zombienet_tests/0006-region-transfer.zndsl +++ b/zombienet_tests/0006-region-transfer.zndsl @@ -7,6 +7,6 @@ rococo-validator02: is up rococo-validator01: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/build/region-transfer/index.js return is 0 within 400 seconds +regionx-collator01: js-script ../e2e_tests/build/region-transfer/index.js return is 0 within 600 seconds sleep 1000 seconds From b64963e88f930ab2fc33bac83d6ce8b1939720f3 Mon Sep 17 00:00:00 2001 From: Sergej Date: Wed, 8 May 2024 11:46:23 +0200 Subject: [PATCH 20/29] merge fixes --- e2e_tests/common.ts | 6 +-- e2e_tests/xc-transfer/asset-transfer.ts | 41 ++----------------- .../region-transfer.ts} | 2 +- ...transfer.toml => 0006-asset-transfer.toml} | 0 ...ansfer.zndsl => 0006-asset-transfer.zndsl} | 2 +- ...ransfer.toml => 0007-region-transfer.toml} | 0 ...nsfer.zndsl => 0007-region-transfer.zndsl} | 2 +- 7 files changed, 8 insertions(+), 45 deletions(-) rename e2e_tests/{region-transfer/index.ts => xc-transfer/region-transfer.ts} (98%) rename zombienet_tests/{0006-xc-transfer.toml => 0006-asset-transfer.toml} (100%) rename zombienet_tests/{0006-xc-transfer.zndsl => 0006-asset-transfer.zndsl} (89%) rename zombienet_tests/{0006-region-transfer.toml => 0007-region-transfer.toml} (100%) rename zombienet_tests/{0006-region-transfer.zndsl => 0007-region-transfer.zndsl} (89%) diff --git a/e2e_tests/common.ts b/e2e_tests/common.ts index 5c86271a..af3294c6 100644 --- a/e2e_tests/common.ts +++ b/e2e_tests/common.ts @@ -58,11 +58,7 @@ async function setupRelayAsset( await submitExtrinsic(signer, sudoCall, {}); } -async function sleep(milliseconds: number) { - return new Promise((resolve) => setTimeout(resolve, milliseconds)); -} - -async function transferRelayAssetToRegionX(amount: string, relayApi: ApiPromise, signer: KeyringPair) { +async function transferRelayAssetToRegionX(amount: bigint, relayApi: ApiPromise, signer: KeyringPair) { const receiverKeypair = new Keyring(); receiverKeypair.addFromAddress(signer.address); diff --git a/e2e_tests/xc-transfer/asset-transfer.ts b/e2e_tests/xc-transfer/asset-transfer.ts index fba88b78..98107b84 100644 --- a/e2e_tests/xc-transfer/asset-transfer.ts +++ b/e2e_tests/xc-transfer/asset-transfer.ts @@ -1,5 +1,5 @@ import { ApiPromise, WsProvider, Keyring } from "@polkadot/api"; -import { RELAY_ASSET_ID, setupRelayAsset, sleep, submitExtrinsic } from "../common"; +import { RELAY_ASSET_ID, setupRelayAsset, sleep, submitExtrinsic, transferRelayAssetToRegionX } from "../common"; import assert from "node:assert"; @@ -45,40 +45,7 @@ async function run(nodeName: string, networkInfo: any, _jsArgs: any) { await assertRegionXBalance(alice.address, 10n ** 12n); await assertRococoBalance(alice.address, 10n ** 18n); - const feeAssetItem = 0; - const weightLimit = "Unlimited"; - const rococoReserveTransfer = rococoApi.tx.xcmPallet.limitedReserveTransferAssets( - { V3: { parents: 0, interior: { X1: { Parachain: 2000 } } } }, //dest - { - V3: { - parents: 0, - interior: { - X1: { - AccountId32: { - chain: "Any", - id: receiverKeypair.pairs[0].publicKey, - }, - }, - }, - }, - }, //beneficiary - { - V3: [ - { - id: { - Concrete: { parents: 0, interior: "Here" }, - }, - fun: { - Fungible: 3n * 10n ** 12n, - }, - }, - ], - }, //asset - feeAssetItem, - weightLimit - ); - await submitExtrinsic(alice, rococoReserveTransfer, {}); - + transferRelayAssetToRegionX(3n * 10n ** 12n, rococoApi, alice); await sleep(5 * 1000); await assertRegionXBalance(alice.address, 4n * 10n ** 12n); @@ -111,8 +78,8 @@ async function run(nodeName: string, networkInfo: any, _jsArgs: any) { }, ], }, //asset - feeAssetItem, - weightLimit + 0, + "Unlimited" ); await submitExtrinsic(alice, regionXReserveTransfer, {}); diff --git a/e2e_tests/region-transfer/index.ts b/e2e_tests/xc-transfer/region-transfer.ts similarity index 98% rename from e2e_tests/region-transfer/index.ts rename to e2e_tests/xc-transfer/region-transfer.ts index 33ee23e7..94255457 100644 --- a/e2e_tests/region-transfer/index.ts +++ b/e2e_tests/xc-transfer/region-transfer.ts @@ -83,7 +83,7 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { ); await submitExtrinsic(alice, reserveTransferToRegionX, {}); - await transferRelayAssetToRegionX((10n**12n).toString(), rococoApi, alice); + await transferRelayAssetToRegionX(10n**12n, rococoApi, alice); const fundSovereignAccount = coretimeApi.tx.balances.forceSetBalance(PARA_SOVEREIGN_ACCOUNT, 1000 * UNIT); await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(fundSovereignAccount), {}); diff --git a/zombienet_tests/0006-xc-transfer.toml b/zombienet_tests/0006-asset-transfer.toml similarity index 100% rename from zombienet_tests/0006-xc-transfer.toml rename to zombienet_tests/0006-asset-transfer.toml diff --git a/zombienet_tests/0006-xc-transfer.zndsl b/zombienet_tests/0006-asset-transfer.zndsl similarity index 89% rename from zombienet_tests/0006-xc-transfer.zndsl rename to zombienet_tests/0006-asset-transfer.zndsl index 55ba38de..5c838441 100644 --- a/zombienet_tests/0006-xc-transfer.zndsl +++ b/zombienet_tests/0006-asset-transfer.zndsl @@ -1,5 +1,5 @@ Description: Cross chain transfer between RegionX and the relay chain -Network: ./0006-xc-transfer.toml +Network: ./0006-asset-transfer.toml Creds: config rococo-validator01: is up diff --git a/zombienet_tests/0006-region-transfer.toml b/zombienet_tests/0007-region-transfer.toml similarity index 100% rename from zombienet_tests/0006-region-transfer.toml rename to zombienet_tests/0007-region-transfer.toml diff --git a/zombienet_tests/0006-region-transfer.zndsl b/zombienet_tests/0007-region-transfer.zndsl similarity index 89% rename from zombienet_tests/0006-region-transfer.zndsl rename to zombienet_tests/0007-region-transfer.zndsl index 4c745193..df421847 100644 --- a/zombienet_tests/0006-region-transfer.zndsl +++ b/zombienet_tests/0007-region-transfer.zndsl @@ -1,5 +1,5 @@ Description: Native currency fee payment -Network: ./0006-region-transfer.toml +Network: ./0007-region-transfer.toml Creds: config rococo-validator01: is up From 8e0375ed4bb602da7a0c28a7fc2663c6c74d38f5 Mon Sep 17 00:00:00 2001 From: Sergej Date: Wed, 8 May 2024 15:31:36 +0200 Subject: [PATCH 21/29] fixes --- e2e_tests/common.ts | 6 ++-- e2e_tests/xc-transfer/asset-transfer.ts | 4 +-- e2e_tests/xc-transfer/region-transfer.ts | 39 ++++++++++++++++------ runtime/regionx/src/xcm_config.rs | 5 ++- zombienet_tests/0007-region-transfer.zndsl | 4 +-- 5 files changed, 36 insertions(+), 22 deletions(-) diff --git a/e2e_tests/common.ts b/e2e_tests/common.ts index af3294c6..81cc0f7a 100644 --- a/e2e_tests/common.ts +++ b/e2e_tests/common.ts @@ -58,14 +58,14 @@ async function setupRelayAsset( await submitExtrinsic(signer, sudoCall, {}); } -async function transferRelayAssetToRegionX(amount: bigint, relayApi: ApiPromise, signer: KeyringPair) { +async function transferRelayAssetToPara(amount: bigint, paraId: number, relayApi: ApiPromise, signer: KeyringPair) { const receiverKeypair = new Keyring(); receiverKeypair.addFromAddress(signer.address); const feeAssetItem = 0; const weightLimit = "Unlimited"; const reserveTransfer = relayApi.tx.xcmPallet.limitedReserveTransferAssets( - { V3: { parents: 0, interior: { X1: { Parachain: 2000 } } } }, //dest + { V3: { parents: 0, interior: { X1: { Parachain: paraId } } } }, //dest { V3: { parents: 0, @@ -101,4 +101,4 @@ async function sleep(milliseconds: number) { return new Promise(resolve => setTimeout(resolve, milliseconds)); } -export { submitExtrinsic, setupRelayAsset, transferRelayAssetToRegionX, sleep, RELAY_ASSET_ID } +export { submitExtrinsic, setupRelayAsset, transferRelayAssetToPara, sleep, RELAY_ASSET_ID } diff --git a/e2e_tests/xc-transfer/asset-transfer.ts b/e2e_tests/xc-transfer/asset-transfer.ts index 98107b84..ab26329b 100644 --- a/e2e_tests/xc-transfer/asset-transfer.ts +++ b/e2e_tests/xc-transfer/asset-transfer.ts @@ -1,5 +1,5 @@ import { ApiPromise, WsProvider, Keyring } from "@polkadot/api"; -import { RELAY_ASSET_ID, setupRelayAsset, sleep, submitExtrinsic, transferRelayAssetToRegionX } from "../common"; +import { RELAY_ASSET_ID, setupRelayAsset, sleep, submitExtrinsic, transferRelayAssetToPara } from "../common"; import assert from "node:assert"; @@ -45,7 +45,7 @@ async function run(nodeName: string, networkInfo: any, _jsArgs: any) { await assertRegionXBalance(alice.address, 10n ** 12n); await assertRococoBalance(alice.address, 10n ** 18n); - transferRelayAssetToRegionX(3n * 10n ** 12n, rococoApi, alice); + transferRelayAssetToPara(3n * 10n ** 12n, 2000, rococoApi, alice); await sleep(5 * 1000); await assertRegionXBalance(alice.address, 4n * 10n ** 12n); diff --git a/e2e_tests/xc-transfer/region-transfer.ts b/e2e_tests/xc-transfer/region-transfer.ts index 94255457..00740f20 100644 --- a/e2e_tests/xc-transfer/region-transfer.ts +++ b/e2e_tests/xc-transfer/region-transfer.ts @@ -1,12 +1,10 @@ import { ApiPromise, WsProvider, Keyring } from "@polkadot/api"; import { CONFIG, INITIAL_PRICE, UNIT, CORE_COUNT } from "../consts"; -import { submitExtrinsic, sleep, transferRelayAssetToRegionX, setupRelayAsset } from "../common"; +import { submitExtrinsic, sleep, setupRelayAsset, transferRelayAssetToPara } from "../common"; import { KeyringPair } from "@polkadot/keyring/types"; import { getEncodedRegionId, Id, RegionId } from "coretime-utils"; import assert from 'node:assert'; -const PARA_SOVEREIGN_ACCOUNT = "5Eg2fntJ27qsari4FGrGhrMqKFDRnkNSR6UshkZYBGXmSuC8"; - async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { const { wsUri: regionXUri } = networkInfo.nodesByName["regionx-collator01"]; const { wsUri: coretimeUri } = networkInfo.nodesByName["coretime-collator01"]; @@ -25,16 +23,17 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setCoretimeXcmVersion), {}); await submitExtrinsic(alice, rococoApi.tx.sudo.sudo(setRelayXcmVersion), {}); + await setupRelayAsset(regionXApi, alice); + await openHrmpChannel(alice, rococoApi, 1005, 2000); await openHrmpChannel(alice, rococoApi, 2000, 1005); - await setupRelayAsset(regionXApi, alice); + await transferRelayAssetToPara(10n**12n, 2000, rococoApi, alice); + await transferRelayAssetToPara(10n**12n, 1005, rococoApi, alice); await configureBroker(coretimeApi, alice); await startSales(coretimeApi, alice); - await sleep(2000); - const setBalanceCall = coretimeApi.tx.balances.forceSetBalance(alice.address, 1000 * UNIT); await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setBalanceCall), {}); @@ -63,6 +62,17 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { }, //beneficiary { V3: [ + { + id: { + Concrete: { + parents: 1, + interior: "Here", + }, + }, + fun: { + Fungible: 10n**10n + }, + }, // ^^ fee payment asset { id: { Concrete: { @@ -83,11 +93,9 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { ); await submitExtrinsic(alice, reserveTransferToRegionX, {}); - await transferRelayAssetToRegionX(10n**12n, rococoApi, alice); - const fundSovereignAccount = coretimeApi.tx.balances.forceSetBalance(PARA_SOVEREIGN_ACCOUNT, 1000 * UNIT); - await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(fundSovereignAccount), {}); + await sleep(5000); - const regions = (await regionXApi.query.regions.regions.entries()); + var regions = (await regionXApi.query.regions.regions.entries()); assert.equal(regions.length, 1); assert.deepStrictEqual(regions[0][0].toHuman(), [regionId]); assert.deepStrictEqual(regions[0][1].toHuman(), { owner: alice.address, record: 'Pending' }); @@ -119,7 +127,7 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { fun: { Fungible: 10n**10n }, - }, + }, // ^^ fee payment asset { id: { Concrete: { @@ -139,6 +147,15 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { weightLimit, ); await submitExtrinsic(alice, reserveTransferToCoretime, {}); + await sleep(5000); + + var regions = (await regionXApi.query.regions.regions.entries()); + assert.equal(regions.length, 0); + + var regions = (await coretimeApi.query.broker.regions.entries()); + assert.equal(regions.length, 1); + assert.deepStrictEqual(regions[0][0].toHuman(), [regionId]); + assert.equal((regions[0][1].toHuman() as any).owner, alice.address); } async function openHrmpChannel(signer: KeyringPair, relayApi: ApiPromise, senderParaId: number, recipientParaId: number) { diff --git a/runtime/regionx/src/xcm_config.rs b/runtime/regionx/src/xcm_config.rs index 58728bee..11cc1bc6 100644 --- a/runtime/regionx/src/xcm_config.rs +++ b/runtime/regionx/src/xcm_config.rs @@ -33,8 +33,8 @@ use sp_runtime::traits::{AccountIdConversion, Convert}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, - AllowUnpaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, - FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, ParentIsPreset, RelayChainAsNative, + DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, + FrameTransactionalProcessor, IsConcrete, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, @@ -169,7 +169,6 @@ pub type Barrier = TrailingSetTopicAsId< TakeWeightCredit, WithComputedOrigin< ( - AllowUnpaidExecutionFrom, // <- TODO: remove AllowTopLevelPaidExecutionFrom, AllowExplicitUnpaidExecutionFrom, // ^^^ Parent and its exec plurality get free execution diff --git a/zombienet_tests/0007-region-transfer.zndsl b/zombienet_tests/0007-region-transfer.zndsl index df421847..7b87cfb0 100644 --- a/zombienet_tests/0007-region-transfer.zndsl +++ b/zombienet_tests/0007-region-transfer.zndsl @@ -7,6 +7,4 @@ rococo-validator02: is up rococo-validator01: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/build/region-transfer/index.js return is 0 within 600 seconds - -sleep 1000 seconds +regionx-collator01: js-script ../e2e_tests/build/xc-transfer/region-transfer.js return is 0 within 600 seconds From ac4ff0e0a186a44c38c0b045196a6d5bf1fdd342 Mon Sep 17 00:00:00 2001 From: Sergej Date: Wed, 8 May 2024 15:51:53 +0200 Subject: [PATCH 22/29] small fixes --- e2e_tests/xc-transfer/region-transfer.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/e2e_tests/xc-transfer/region-transfer.ts b/e2e_tests/xc-transfer/region-transfer.ts index 00740f20..4278f38e 100644 --- a/e2e_tests/xc-transfer/region-transfer.ts +++ b/e2e_tests/xc-transfer/region-transfer.ts @@ -28,6 +28,7 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { await openHrmpChannel(alice, rococoApi, 1005, 2000); await openHrmpChannel(alice, rococoApi, 2000, 1005); + // Needed for fee payment await transferRelayAssetToPara(10n**12n, 2000, rococoApi, alice); await transferRelayAssetToPara(10n**12n, 1005, rococoApi, alice); @@ -169,16 +170,7 @@ async function openHrmpChannel(signer: KeyringPair, relayApi: ApiPromise, sender const openHrmp = relayApi.tx.parasSudoWrapper.sudoEstablishHrmpChannel(...newHrmpChannel); const sudoCall = relayApi.tx.sudo.sudo(openHrmp); - const callTx = async (resolve: any) => { - const unsub = await sudoCall.signAndSend(signer, (result) => { - if (result.status.isInBlock) { - unsub(); - resolve(); - } - }); - }; - - return new Promise(callTx); + return submitExtrinsic(signer, sudoCall, {}); } async function configureBroker(coretimeApi: ApiPromise, signer: KeyringPair): Promise { From bcb7a3421f20b43ff5de9aa55de2443da73e88f3 Mon Sep 17 00:00:00 2001 From: cuteolaf Date: Wed, 8 May 2024 15:09:12 +0000 Subject: [PATCH 23/29] format & refactor --- e2e_tests/xc-transfer/region-transfer.ts | 397 ++++++++++++----------- 1 file changed, 205 insertions(+), 192 deletions(-) diff --git a/e2e_tests/xc-transfer/region-transfer.ts b/e2e_tests/xc-transfer/region-transfer.ts index 4278f38e..348b61d3 100644 --- a/e2e_tests/xc-transfer/region-transfer.ts +++ b/e2e_tests/xc-transfer/region-transfer.ts @@ -3,215 +3,228 @@ import { CONFIG, INITIAL_PRICE, UNIT, CORE_COUNT } from "../consts"; import { submitExtrinsic, sleep, setupRelayAsset, transferRelayAssetToPara } from "../common"; import { KeyringPair } from "@polkadot/keyring/types"; import { getEncodedRegionId, Id, RegionId } from "coretime-utils"; -import assert from 'node:assert'; +import assert from "node:assert"; async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { - const { wsUri: regionXUri } = networkInfo.nodesByName["regionx-collator01"]; - const { wsUri: coretimeUri } = networkInfo.nodesByName["coretime-collator01"]; - const { wsUri: rococoUri } = networkInfo.nodesByName["rococo-validator01"]; - - const regionXApi = await ApiPromise.create({ provider: new WsProvider(regionXUri) }); - const rococoApi = await ApiPromise.create({ provider: new WsProvider(rococoUri), types: { Id } }); - const coretimeApi = await ApiPromise.create({ provider: new WsProvider(coretimeUri), types: { Id } }); - - // account to submit tx - const keyring = new Keyring({ type: "sr25519" }); - const alice = keyring.addFromUri("//Alice"); - - const setCoretimeXcmVersion = coretimeApi.tx.polkadotXcm.forceDefaultXcmVersion([3]); - const setRelayXcmVersion = rococoApi.tx.xcmPallet.forceDefaultXcmVersion([3]); - await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setCoretimeXcmVersion), {}); - await submitExtrinsic(alice, rococoApi.tx.sudo.sudo(setRelayXcmVersion), {}); - - await setupRelayAsset(regionXApi, alice); - - await openHrmpChannel(alice, rococoApi, 1005, 2000); - await openHrmpChannel(alice, rococoApi, 2000, 1005); - - // Needed for fee payment - await transferRelayAssetToPara(10n**12n, 2000, rococoApi, alice); - await transferRelayAssetToPara(10n**12n, 1005, rococoApi, alice); - - await configureBroker(coretimeApi, alice); - await startSales(coretimeApi, alice); - - const setBalanceCall = coretimeApi.tx.balances.forceSetBalance(alice.address, 1000 * UNIT); - await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(setBalanceCall), {}); - - const regionId = await purchaseRegion(coretimeApi, alice); - if(!regionId) throw new Error("RegionId not found"); - - const receiverKeypair = new Keyring(); - receiverKeypair.addFromAddress(alice.address); - - const feeAssetItem = 0; - const weightLimit = "Unlimited"; - const reserveTransferToRegionX = coretimeApi.tx.polkadotXcm.limitedReserveTransferAssets( - { V3: { parents: 1, interior: { X1: { Parachain: 2000 } } } }, //dest - { - V3: { - parents: 0, - interior: { - X1: { - AccountId32: { - chain: "Any", - id: receiverKeypair.pairs[0].publicKey, - }, - }, - }, - }, - }, //beneficiary - { - V3: [ - { - id: { - Concrete: { - parents: 1, - interior: "Here", - }, - }, - fun: { - Fungible: 10n**10n - }, - }, // ^^ fee payment asset - { - id: { - Concrete: { - parents: 0, - interior: { X1: { PalletInstance: 50 } }, - }, - }, - fun: { - NonFungible: { - Index: getEncodedRegionId(regionId, coretimeApi).toString() - } - }, - }, - ], - }, //asset - feeAssetItem, - weightLimit, - ); - await submitExtrinsic(alice, reserveTransferToRegionX, {}); - - await sleep(5000); - - var regions = (await regionXApi.query.regions.regions.entries()); - assert.equal(regions.length, 1); - assert.deepStrictEqual(regions[0][0].toHuman(), [regionId]); - assert.deepStrictEqual(regions[0][1].toHuman(), { owner: alice.address, record: 'Pending' }); - - const reserveTransferToCoretime = regionXApi.tx.polkadotXcm.limitedReserveTransferAssets( - { V3: { parents: 1, interior: { X1: { Parachain: 1005 } } } }, // dest - { - V3: { - parents: 0, - interior: { - X1: { - AccountId32: { - chain: "Any", - id: receiverKeypair.pairs[0].publicKey, - }, - }, - }, - }, - }, // ^^ beneficiary - { - V3: [ - { - id: { - Concrete: { - parents: 1, - interior: "Here", - }, - }, - fun: { - Fungible: 10n**10n - }, - }, // ^^ fee payment asset - { - id: { - Concrete: { - parents: 1, - interior: { X2: [ {Parachain: 1005}, { PalletInstance: 50 }] }, - }, - }, - fun: { - NonFungible: { - Index: getEncodedRegionId(regionId, regionXApi).toString() - } - }, - }, - ], - }, // ^^ asset - feeAssetItem, - weightLimit, - ); - await submitExtrinsic(alice, reserveTransferToCoretime, {}); - await sleep(5000); - - var regions = (await regionXApi.query.regions.regions.entries()); - assert.equal(regions.length, 0); - - var regions = (await coretimeApi.query.broker.regions.entries()); - assert.equal(regions.length, 1); - assert.deepStrictEqual(regions[0][0].toHuman(), [regionId]); - assert.equal((regions[0][1].toHuman() as any).owner, alice.address); + const { wsUri: regionXUri } = networkInfo.nodesByName["regionx-collator01"]; + const { wsUri: coretimeUri } = networkInfo.nodesByName["coretime-collator01"]; + const { wsUri: rococoUri } = networkInfo.nodesByName["rococo-validator01"]; + + const regionXApi = await ApiPromise.create({ provider: new WsProvider(regionXUri) }); + const rococoApi = await ApiPromise.create({ + provider: new WsProvider(rococoUri), + types: { Id }, + }); + const coretimeApi = await ApiPromise.create({ + provider: new WsProvider(coretimeUri), + types: { Id }, + }); + + // account to submit tx + const keyring = new Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + + const txSetCoretimeXcmVersion = coretimeApi.tx.polkadotXcm.forceDefaultXcmVersion([3]); + const txSetRelayXcmVersion = rococoApi.tx.xcmPallet.forceDefaultXcmVersion([3]); + await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(txSetCoretimeXcmVersion), {}); + await submitExtrinsic(alice, rococoApi.tx.sudo.sudo(txSetRelayXcmVersion), {}); + + await setupRelayAsset(regionXApi, alice); + + await openHrmpChannel(alice, rococoApi, 1005, 2000); + await openHrmpChannel(alice, rococoApi, 2000, 1005); + + // Needed for fee payment + await transferRelayAssetToPara(10n ** 12n, 2000, rococoApi, alice); + await transferRelayAssetToPara(10n ** 12n, 1005, rococoApi, alice); + + await configureBroker(coretimeApi, alice); + await startSales(coretimeApi, alice); + + const txSetBalance = coretimeApi.tx.balances.forceSetBalance(alice.address, 1000 * UNIT); + await submitExtrinsic(alice, coretimeApi.tx.sudo.sudo(txSetBalance), {}); + + const regionId = await purchaseRegion(coretimeApi, alice); + if (!regionId) throw new Error("RegionId not found"); + + const receiverKeypair = new Keyring(); + receiverKeypair.addFromAddress(alice.address); + + const feeAssetItem = 0; + const weightLimit = "Unlimited"; + const reserveTransferToRegionX = coretimeApi.tx.polkadotXcm.limitedReserveTransferAssets( + { V3: { parents: 1, interior: { X1: { Parachain: 2000 } } } }, //dest + { + V3: { + parents: 0, + interior: { + X1: { + AccountId32: { + chain: "Any", + id: receiverKeypair.pairs[0].publicKey, + }, + }, + }, + }, + }, //beneficiary + { + V3: [ + { + id: { + Concrete: { + parents: 1, + interior: "Here", + }, + }, + fun: { + Fungible: 10n ** 10n, + }, + }, // ^^ fee payment asset + { + id: { + Concrete: { + parents: 0, + interior: { X1: { PalletInstance: 50 } }, + }, + }, + fun: { + NonFungible: { + Index: getEncodedRegionId(regionId, coretimeApi).toString(), + }, + }, + }, + ], + }, //asset + feeAssetItem, + weightLimit + ); + await submitExtrinsic(alice, reserveTransferToRegionX, {}); + + await sleep(5000); + + var regions = await regionXApi.query.regions.regions.entries(); + assert.equal(regions.length, 1); + assert.deepStrictEqual(regions[0][0].toHuman(), [regionId]); + assert.deepStrictEqual(regions[0][1].toHuman(), { owner: alice.address, record: "Pending" }); + + const reserveTransferToCoretime = regionXApi.tx.polkadotXcm.limitedReserveTransferAssets( + { V3: { parents: 1, interior: { X1: { Parachain: 1005 } } } }, // dest + { + V3: { + parents: 0, + interior: { + X1: { + AccountId32: { + chain: "Any", + id: receiverKeypair.pairs[0].publicKey, + }, + }, + }, + }, + }, // ^^ beneficiary + { + V3: [ + { + id: { + Concrete: { + parents: 1, + interior: "Here", + }, + }, + fun: { + Fungible: 10n ** 10n, + }, + }, // ^^ fee payment asset + { + id: { + Concrete: { + parents: 1, + // chain: Rococo-Coretime, pallet: pallet_broker + interior: { X2: [{ Parachain: 1005 }, { PalletInstance: 50 }] }, + }, + }, + fun: { + NonFungible: { + Index: getEncodedRegionId(regionId, regionXApi).toString(), + }, + }, + }, + ], + }, // ^^ asset + feeAssetItem, + weightLimit + ); + await submitExtrinsic(alice, reserveTransferToCoretime, {}); + await sleep(5000); + + var regions = await regionXApi.query.regions.regions.entries(); + assert.equal(regions.length, 0); + + var regions = await coretimeApi.query.broker.regions.entries(); + assert.equal(regions.length, 1); + assert.deepStrictEqual(regions[0][0].toHuman(), [regionId]); + assert.equal((regions[0][1].toHuman() as any).owner, alice.address); } -async function openHrmpChannel(signer: KeyringPair, relayApi: ApiPromise, senderParaId: number, recipientParaId: number) { - const newHrmpChannel = [ - senderParaId, - recipientParaId, - 8, // Max capacity - 102400, // Max message size - ]; - - const openHrmp = relayApi.tx.parasSudoWrapper.sudoEstablishHrmpChannel(...newHrmpChannel); - const sudoCall = relayApi.tx.sudo.sudo(openHrmp); - - return submitExtrinsic(signer, sudoCall, {}); +async function openHrmpChannel( + signer: KeyringPair, + relayApi: ApiPromise, + senderParaId: number, + recipientParaId: number +) { + const openHrmp = relayApi.tx.parasSudoWrapper.sudoEstablishHrmpChannel( + senderParaId, // sender + recipientParaId, // recipient + 8, // Max capacity + 102400 // Max message size + ); + const sudoCall = relayApi.tx.sudo.sudo(openHrmp); + + return submitExtrinsic(signer, sudoCall, {}); } async function configureBroker(coretimeApi: ApiPromise, signer: KeyringPair): Promise { - const configCall = coretimeApi.tx.broker.configure(CONFIG); - const sudo = coretimeApi.tx.sudo.sudo(configCall) - return submitExtrinsic(signer, sudo, {}); + const configCall = coretimeApi.tx.broker.configure(CONFIG); + const sudo = coretimeApi.tx.sudo.sudo(configCall); + return submitExtrinsic(signer, sudo, {}); } async function startSales(coretimeApi: ApiPromise, signer: KeyringPair): Promise { - const startSaleCall = coretimeApi.tx.broker.startSales(INITIAL_PRICE, CORE_COUNT); - const sudo = coretimeApi.tx.sudo.sudo(startSaleCall) - return submitExtrinsic(signer, sudo, {}); + const startSaleCall = coretimeApi.tx.broker.startSales(INITIAL_PRICE, CORE_COUNT); + const sudo = coretimeApi.tx.sudo.sudo(startSaleCall); + return submitExtrinsic(signer, sudo, {}); } -async function purchaseRegion(coretimeApi: ApiPromise, buyer: KeyringPair): Promise { - const callTx = async (resolve: (regionId: RegionId | null) => void) => { - const purchase = coretimeApi.tx.broker.purchase(INITIAL_PRICE * 2); - const unsub = await purchase.signAndSend(buyer, async (result: any) => { - if (result.status.isInBlock) { - const regionId = await getRegionId(coretimeApi); - unsub(); - resolve(regionId); - } - }); - }; - - return new Promise(callTx); +async function purchaseRegion( + coretimeApi: ApiPromise, + buyer: KeyringPair +): Promise { + const callTx = async (resolve: (regionId: RegionId | null) => void) => { + const purchase = coretimeApi.tx.broker.purchase(INITIAL_PRICE * 2); + const unsub = await purchase.signAndSend(buyer, async (result: any) => { + if (result.status.isInBlock) { + const regionId = await getRegionId(coretimeApi); + unsub(); + resolve(regionId); + } + }); + }; + + return new Promise(callTx); } async function getRegionId(coretimeApi: ApiPromise): Promise { - const events: any = await coretimeApi.query.system.events(); + const events: any = await coretimeApi.query.system.events(); - for (const record of events) { - const { event } = record; - if (event.section === "broker" && event.method === "Purchased") { - const data = event.data[1].toHuman(); - return data; - } - } + for (const record of events) { + const { event } = record; + if (event.section === "broker" && event.method === "Purchased") { + const data = event.data[1].toHuman(); + return data; + } + } - return null; + return null; } export { run }; From a3b61d18281f5bfcd97ec0736a8fd01790208f57 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Wed, 8 May 2024 17:38:36 +0200 Subject: [PATCH 24/29] Update e2e_tests/xc-transfer/asset-transfer.ts Co-authored-by: cuteolaf --- e2e_tests/xc-transfer/asset-transfer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e_tests/xc-transfer/asset-transfer.ts b/e2e_tests/xc-transfer/asset-transfer.ts index ab26329b..d820db7a 100644 --- a/e2e_tests/xc-transfer/asset-transfer.ts +++ b/e2e_tests/xc-transfer/asset-transfer.ts @@ -45,7 +45,7 @@ async function run(nodeName: string, networkInfo: any, _jsArgs: any) { await assertRegionXBalance(alice.address, 10n ** 12n); await assertRococoBalance(alice.address, 10n ** 18n); - transferRelayAssetToPara(3n * 10n ** 12n, 2000, rococoApi, alice); + await transferRelayAssetToPara(3n * 10n ** 12n, 2000, rococoApi, alice); await sleep(5 * 1000); await assertRegionXBalance(alice.address, 4n * 10n ** 12n); From 65de1ac40b139dd0f35860d61e730c167c9ddff0 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Wed, 8 May 2024 17:38:55 +0200 Subject: [PATCH 25/29] Update e2e_tests/common.ts Co-authored-by: cuteolaf --- e2e_tests/common.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/e2e_tests/common.ts b/e2e_tests/common.ts index 81cc0f7a..f87f1c15 100644 --- a/e2e_tests/common.ts +++ b/e2e_tests/common.ts @@ -58,6 +58,8 @@ async function setupRelayAsset( await submitExtrinsic(signer, sudoCall, {}); } +// Transfer the relay chain asset to the parachain specified by paraId. +// Receiver address is same as the sender's. async function transferRelayAssetToPara(amount: bigint, paraId: number, relayApi: ApiPromise, signer: KeyringPair) { const receiverKeypair = new Keyring(); receiverKeypair.addFromAddress(signer.address); From f56960b53f53c6fbee86baf33de43a6ff3b3d9b3 Mon Sep 17 00:00:00 2001 From: Sergej Date: Wed, 8 May 2024 17:39:59 +0200 Subject: [PATCH 26/29] remove file --- e2e_tests/test.js | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 e2e_tests/test.js diff --git a/e2e_tests/test.js b/e2e_tests/test.js deleted file mode 100644 index ec9db50d..00000000 --- a/e2e_tests/test.js +++ /dev/null @@ -1,10 +0,0 @@ -const { ApiPromise, WsProvider } = require("@polkadot/api"); -const {Id, getEncodedRegionId, CoreMask} = require("coretime-utils"); - -const run = async() => { - const regionXApi = await ApiPromise.create({ provider: new WsProvider("ws://127.0.0.1:33247"), types: {Id} }); - - console.log(getEncodedRegionId({begin: 34, core: 0, mask: new CoreMask("0xffffffffffffffffffff")}, regionXApi).toString()); -} - -run(); \ No newline at end of file From 08330c3cfb8a897279e88c3e7e243f2003433c8c Mon Sep 17 00:00:00 2001 From: Sergej Date: Wed, 8 May 2024 20:09:53 +0200 Subject: [PATCH 27/29] trusted reserves --- e2e_tests/xc-transfer/region-transfer.ts | 7 +++++++ runtime/regionx/src/xcm_config.rs | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/e2e_tests/xc-transfer/region-transfer.ts b/e2e_tests/xc-transfer/region-transfer.ts index 348b61d3..3b329002 100644 --- a/e2e_tests/xc-transfer/region-transfer.ts +++ b/e2e_tests/xc-transfer/region-transfer.ts @@ -5,6 +5,8 @@ import { KeyringPair } from "@polkadot/keyring/types"; import { getEncodedRegionId, Id, RegionId } from "coretime-utils"; import assert from "node:assert"; +const REGIONX_SOVEREIGN_ACCOUNT = "5Eg2fntJ27qsari4FGrGhrMqKFDRnkNSR6UshkZYBGXmSuC8"; + async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { const { wsUri: regionXUri } = networkInfo.nodesByName["regionx-collator01"]; const { wsUri: coretimeUri } = networkInfo.nodesByName["coretime-collator01"]; @@ -107,6 +109,11 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { assert.deepStrictEqual(regions[0][0].toHuman(), [regionId]); assert.deepStrictEqual(regions[0][1].toHuman(), { owner: alice.address, record: "Pending" }); + var regions = await coretimeApi.query.broker.regions.entries(); + assert.equal(regions.length, 1); + assert.deepStrictEqual(regions[0][0].toHuman(), [regionId]); + assert.equal((regions[0][1].toHuman() as any).owner, REGIONX_SOVEREIGN_ACCOUNT); + const reserveTransferToCoretime = regionXApi.tx.polkadotXcm.limitedReserveTransferAssets( { V3: { parents: 1, interior: { X1: { Parachain: 1005 } } } }, // dest { diff --git a/runtime/regionx/src/xcm_config.rs b/runtime/regionx/src/xcm_config.rs index 11cc1bc6..28b5e517 100644 --- a/runtime/regionx/src/xcm_config.rs +++ b/runtime/regionx/src/xcm_config.rs @@ -34,7 +34,7 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, - FrameTransactionalProcessor, IsConcrete, ParentIsPreset, RelayChainAsNative, + FrameTransactionalProcessor, IsConcrete, NativeAsset, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, @@ -48,10 +48,20 @@ parameter_types! { interior: X2(Parachain(CORETIME_CHAIN_PARA_ID), PalletInstance(50)) }; pub const RelayNetwork: Option = None; + pub const CoretimeChainLocation: MultiLocation = MultiLocation { + parents: 1, + interior: X1(Parachain(CORETIME_CHAIN_PARA_ID)) + }; + pub AssetsFromCoretimeChain: (MultiAssetFilter, MultiLocation) = ( + Wild(All), // We can trust system parachains. + CoretimeChainLocation::get() + ); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); } +pub type TrustedReserves = (NativeAsset, xcm_builder::Case); + /// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used /// when determining ownership of accounts for asset transacting and when attempting to use XCM /// `Transact` in order to determine the dispatch Origin. @@ -187,7 +197,7 @@ impl xcm_executor::Config for XcmConfig { // How to withdraw and deposit an asset. type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = Everything; // TODO + type IsReserve = TrustedReserves; type IsTeleporter = (); // Teleporting is disabled. type UniversalLocation = UniversalLocation; type Barrier = Barrier; From 94c2675afdc2788c006e67afe3551afdf6bb678f Mon Sep 17 00:00:00 2001 From: Sergej Date: Thu, 9 May 2024 10:57:42 +0200 Subject: [PATCH 28/29] fix asset-transfer test --- e2e_tests/xc-transfer/asset-transfer.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/e2e_tests/xc-transfer/asset-transfer.ts b/e2e_tests/xc-transfer/asset-transfer.ts index d820db7a..097e0098 100644 --- a/e2e_tests/xc-transfer/asset-transfer.ts +++ b/e2e_tests/xc-transfer/asset-transfer.ts @@ -27,19 +27,19 @@ async function run(nodeName: string, networkInfo: any, _jsArgs: any) { const assertRegionXBalance = async (address: string, balance: bigint) => { const { free } = ( await regionXApi.query.tokens.accounts(address, RELAY_ASSET_ID) - ).toHuman() as any; + ).toJSON() as any; - console.log(`RegionX: ${free}`); - assert(balance - BigInt(free.toString().replace(/,/g, "")) < TOLERANCE); + console.log(`RegionX: ${BigInt(free).toString()} | Expected: ${balance}`); + assert(balance - BigInt(free) < TOLERANCE); }; const assertRococoBalance = async (address: string, balance: bigint) => { const { data: { free }, - } = (await rococoApi.query.system.account(address)).toHuman() as any; + } = (await rococoApi.query.system.account(address)).toJSON() as any; - console.log(`Rococo: ${free}`); - assert(balance - BigInt(free.toString().replace(/,/g, "")) < TOLERANCE); + console.log(`Rococo: ${BigInt(free).toString()} | Expected: ${balance}`); + assert(balance - BigInt(free) < TOLERANCE); }; await assertRegionXBalance(alice.address, 10n ** 12n); @@ -86,7 +86,7 @@ async function run(nodeName: string, networkInfo: any, _jsArgs: any) { await sleep(5 * 1000); - await assertRegionXBalance(alice.address, 4n * 10n ** 12n); + await assertRegionXBalance(alice.address, 3n * 10n ** 12n); await assertRococoBalance(alice.address, 10n ** 18n - 3n * 10n ** 12n); } From 258571ba2dc1f35913bf01fe59dc7ce69aa4a47d Mon Sep 17 00:00:00 2001 From: Sergej Date: Thu, 9 May 2024 13:17:10 +0200 Subject: [PATCH 29/29] small fixes --- e2e_tests/common.ts | 7 +++++-- e2e_tests/governance/native.ts | 1 + e2e_tests/xc-transfer/region-transfer.ts | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/e2e_tests/common.ts b/e2e_tests/common.ts index f87f1c15..dcadfc0c 100644 --- a/e2e_tests/common.ts +++ b/e2e_tests/common.ts @@ -30,7 +30,7 @@ async function submitExtrinsic( async function setupRelayAsset( api: ApiPromise, signer: KeyringPair, - initialBalance: bigint = 10n ** 12n + initialBalance: bigint = 0n ) { const assetMetadata = { decimals: 12, @@ -64,9 +64,12 @@ async function transferRelayAssetToPara(amount: bigint, paraId: number, relayApi const receiverKeypair = new Keyring(); receiverKeypair.addFromAddress(signer.address); + // If system parachain we use teleportation, otherwise we do a reserve transfer. + const transferKind = paraId < 2000 ? 'limitedTeleportAssets' : 'limitedReserveTransferAssets'; + const feeAssetItem = 0; const weightLimit = "Unlimited"; - const reserveTransfer = relayApi.tx.xcmPallet.limitedReserveTransferAssets( + const reserveTransfer = relayApi.tx.xcmPallet[transferKind]( { V3: { parents: 0, interior: { X1: { Parachain: paraId } } } }, //dest { V3: { diff --git a/e2e_tests/governance/native.ts b/e2e_tests/governance/native.ts index 40c78e7d..3fb59b93 100644 --- a/e2e_tests/governance/native.ts +++ b/e2e_tests/governance/native.ts @@ -11,6 +11,7 @@ async function run(nodeName: string, networkInfo: any, _jsArgs: any) { const keyring = new Keyring({ type: "sr25519" }); const alice = keyring.addFromUri("//Alice"); + // relay asset is needed for storing the preimage. await setupRelayAsset(api, alice); const spendCallBytes = api.tx.treasury.spendLocal(10n ** 6n, alice.address).toU8a(); diff --git a/e2e_tests/xc-transfer/region-transfer.ts b/e2e_tests/xc-transfer/region-transfer.ts index 3b329002..9d635984 100644 --- a/e2e_tests/xc-transfer/region-transfer.ts +++ b/e2e_tests/xc-transfer/region-transfer.ts @@ -37,8 +37,8 @@ async function run(_nodeName: any, networkInfo: any, _jsArgs: any) { await openHrmpChannel(alice, rococoApi, 2000, 1005); // Needed for fee payment + // The Coretime chain account by default has tokens for fee payment. await transferRelayAssetToPara(10n ** 12n, 2000, rococoApi, alice); - await transferRelayAssetToPara(10n ** 12n, 1005, rococoApi, alice); await configureBroker(coretimeApi, alice); await startSales(coretimeApi, alice);