From 9335638dc5a757e007040cc1b0e618c245f80281 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Sat, 27 Apr 2024 09:16:36 +0200 Subject: [PATCH 1/8] Preimage and scheduler (#101) * Pallet preimage & scheduler * scheduler --- Cargo.lock | 2 ++ Cargo.toml | 2 ++ runtime/regionx/Cargo.toml | 8 +++++++ runtime/regionx/src/lib.rs | 45 +++++++++++++++++++++++++++++++++++++- 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index a9f88f45..d7796cb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9422,8 +9422,10 @@ dependencies = [ "pallet-ismp-runtime-api", "pallet-message-queue", "pallet-multisig", + "pallet-preimage", "pallet-proxy", "pallet-regions", + "pallet-scheduler", "pallet-session", "pallet-sudo", "pallet-timestamp", diff --git a/Cargo.toml b/Cargo.toml index fcfaafa4..a1e9c22e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,8 @@ pallet-transaction-payment-rpc-runtime-api = { version = "28.0.0", default-featu pallet-message-queue = { version = "31.0.0", default-features = false } pallet-multisig = { version = "28.0.0", default-features = false } pallet-proxy = { version = "28.0.0", default-features = false } +pallet-preimage = { version = "28.0.0", default-features = false } +pallet-scheduler = { version = "29.0.0", default-features = false } pallet-utility = { version = "28.0.0", default-features = false } sp-api = { version = "26.0.0", default-features = false } sp-blockchain = { version = "28.0.0", default-features = false } diff --git a/runtime/regionx/Cargo.toml b/runtime/regionx/Cargo.toml index 2c9bc985..2aa5edf7 100644 --- a/runtime/regionx/Cargo.toml +++ b/runtime/regionx/Cargo.toml @@ -52,8 +52,10 @@ pallet-balances = { workspace = true } pallet-message-queue = { workspace = true } pallet-multisig = { workspace = true } pallet-proxy = { workspace = true } +pallet-preimage = { workspace = true } pallet-session = { workspace = true } pallet-sudo = { workspace = true } +pallet-scheduler = { workspace = true } pallet-timestamp = { workspace = true } pallet-transaction-payment = { workspace = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true } @@ -134,8 +136,10 @@ std = [ "regionx-primitives/std", "pallet-multisig/std", "pallet-proxy/std", + "pallet-preimage/std", "pallet-session/std", "pallet-sudo/std", + "pallet-scheduler/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", @@ -185,8 +189,10 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", + "pallet-preimage/runtime-benchmarks", "pallet-regions/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", + "pallet-scheduler/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", @@ -222,9 +228,11 @@ try-runtime = [ "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-proxy/try-runtime", + "pallet-preimage/try-runtime", "pallet-regions/try-runtime", "pallet-session/try-runtime", "pallet-sudo/try-runtime", + "pallet-scheduler/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", "pallet-utility/try-runtime", diff --git a/runtime/regionx/src/lib.rs b/runtime/regionx/src/lib.rs index 334a7340..b7826898 100644 --- a/runtime/regionx/src/lib.rs +++ b/runtime/regionx/src/lib.rs @@ -33,7 +33,9 @@ use impls::*; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; -use frame_support::traits::TransformOrigin; +use frame_support::traits::{ + fungible::HoldConsideration, EqualPrivilegeOnly, LinearStoragePrice, TransformOrigin, +}; use pallet_regions::primitives::StateMachineHeightProvider as StateMachineHeightProviderT; use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; @@ -650,6 +652,43 @@ impl pallet_proxy::Config for Runtime { type AnnouncementDepositFactor = AnnouncementDepositFactor; } +parameter_types! { + pub const PreimageBaseDeposit: Balance = deposit(2, 64); + pub const PreimageByteDeposit: Balance = deposit(0, 1); + pub const PreimageHoldReason: RuntimeHoldReason = + RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage); +} + +impl pallet_preimage::Config for Runtime { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type Consideration = HoldConsideration< + AccountId, + Balances, + PreimageHoldReason, + LinearStoragePrice, + >; +} + +parameter_types! { + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_scheduler::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = ConstU32<10>; + type WeightInfo = (); + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = Preimage; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -659,6 +698,8 @@ construct_runtime!( ParachainSystem: cumulus_pallet_parachain_system = 1, Timestamp: pallet_timestamp = 2, ParachainInfo: parachain_info = 3, + Preimage: pallet_preimage = 4, + Scheduler: pallet_scheduler = 5, // Monetary stuff. Balances: pallet_balances = 10, @@ -707,9 +748,11 @@ mod benches { [pallet_session, SessionBench::] [pallet_multisig, Multisig] [pallet_proxy, Proxy] + [pallet_proxy, Preimage] [pallet_timestamp, Timestamp] [pallet_utility, Utility] [pallet_sudo, Sudo] + [pallet_proxy, Scheduler] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_regions, Regions] From 696850df2a5c99a7c64ea95277956a6c77307bc8 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Sat, 27 Apr 2024 11:07:05 +0200 Subject: [PATCH 2/8] Handle incoming relay chain asset transfers (#99) * MultiCurrency Asset Transactor * fee payment with rc token * prettier * handle unknown tokens * fmt * some improvements * fix block-production.zndsl * upgrade version of pallet-collator-selection --------- Co-authored-by: cuteolaf --- Cargo.lock | 33 +++++++ Cargo.toml | 4 +- README.md | 23 ++++- e2e_tests/custom-fee-payment.js | 87 +++++++++++++++---- node/src/chain_spec.rs | 4 +- runtime/regionx/Cargo.toml | 4 + runtime/regionx/src/lib.rs | 5 ++ runtime/regionx/src/xcm_config.rs | 73 ++++++++++++---- zombienet_tests/0001-block-production.zndsl | 2 +- zombienet_tests/0003-custom-fee-payment.toml | 4 +- zombienet_tests/0003-custom-fee-payment.zndsl | 6 +- 11 files changed, 197 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7796cb9..8e7052c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5980,6 +5980,22 @@ dependencies = [ "staging-xcm", ] +[[package]] +name = "orml-unknown-tokens" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12c26e74a7407bd6bccc8d123a4f6d60e5b01188c135804dc1e48ca98c49dbf6" +dependencies = [ + "frame-support", + "frame-system", + "orml-xcm-support", + "parity-scale-codec", + "scale-info", + "serde", + "sp-std", + "staging-xcm", +] + [[package]] name = "orml-utilities" version = "0.7.0" @@ -5996,6 +6012,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "orml-xcm-support" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb61790b9ce5698f7026bbf9ebd932df782a425b3551e9dd04300cb4eace179" +dependencies = [ + "frame-support", + "orml-traits", + "parity-scale-codec", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + [[package]] name = "pallet-asset-rate" version = "7.0.0" @@ -9412,6 +9443,8 @@ dependencies = [ "orml-currencies", "orml-tokens", "orml-traits", + "orml-unknown-tokens", + "orml-xcm-support", "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-aura", diff --git a/Cargo.toml b/Cargo.toml index a1e9c22e..a0a01304 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,7 +87,7 @@ cumulus-pallet-xcmp-queue = { version = "0.7.0", default-features = false } cumulus-primitives-core = { version = "0.7.0", default-features = false } cumulus-primitives-timestamp = { version = "0.7.0", default-features = false } cumulus-primitives-utility = { version = "0.7.3", default-features = false } -pallet-collator-selection = { version = "9.0.0", default-features = false } +pallet-collator-selection = { version = "9.0.2", default-features = false } parachain-info = { version = "0.7.0", package = "staging-parachain-info", default-features = false } parachains-common = { version = "7.0.0", default-features = false } sp-timestamp = { version = "26.0.0", default-features = false } @@ -141,6 +141,8 @@ orml-asset-registry = { version = "0.7.0", default-features = false } orml-currencies = { version = "0.7.0", default-features = false } orml-tokens = { version = "0.7.0", default-features = false } orml-traits = { version = "0.7.0", default-features = false } +orml-unknown-tokens = { version = "0.7.0", default-features = false } +orml-xcm-support = { version = "0.7.0", default-features = false } # Polytope Labs ismp = { git="https://github.com/Szegoo/hyperbridge.git", branch="fix-to-string", default-features = false } diff --git a/README.md b/README.md index 19a4f421..42604cb2 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,23 @@ export PATH=/home//RegionX-Node/:$PATH ``` -4. Run the test: +4. Run the tests: + + - block production - ``` - zombienet-linux -p native test ./zombienet_tests/0001-smoke-test.zndsl - ``` + + ``` + zombienet-linux -p native test ./zombienet_tests/0001-block-production.zndsl + ``` + + - native fee payment + + ``` + zombienet-linux -p native test ./zombienet_tests/0002-native-fee-payment.zndsl + ``` + + - custom fee payment + + ``` + zombienet-linux -p native test ./zombienet_tests/0003-custom-fee-payment.zndsl + ``` \ No newline at end of file diff --git a/e2e_tests/custom-fee-payment.js b/e2e_tests/custom-fee-payment.js index 95c52c01..9e1c058b 100644 --- a/e2e_tests/custom-fee-payment.js +++ b/e2e_tests/custom-fee-payment.js @@ -1,12 +1,17 @@ -const { ApiPromise, WsProvider } = require("@polkadot/api"); +const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); const { submitExtrinsic } = require("./common"); -const ASSET_ID = 42; +const RELAY_ASSET_ID = 1; async function run(nodeName, networkInfo, _jsArgs) { - const { wsUri } = networkInfo.nodesByName[nodeName]; - const api = await ApiPromise.create({ - provider: new WsProvider(wsUri), + const { wsUri: regionXUri } = networkInfo.nodesByName[nodeName]; + const { wsUri: rococoUri } = networkInfo.nodesByName["rococo-validator01"]; + + const rococoApi = await ApiPromise.create({ + provider: new WsProvider(rococoUri), + }); + const regionXApi = await ApiPromise.create({ + provider: new WsProvider(regionXUri), signedExtensions: { ChargeAssetTxPayment: { extrinsic: { @@ -22,27 +27,73 @@ async function run(nodeName, networkInfo, _jsArgs) { const keyring = new zombie.Keyring({ type: "sr25519" }); const alice = keyring.addFromUri("//Alice"); + const setXcmVersion = rococoApi.tx.xcmPallet.forceDefaultXcmVersion([3]); + await submitExtrinsic(alice, rococoApi.tx.sudo.sudo(setXcmVersion), {}); + const assetMetadata = { - decimals: 10, - name: "DOT", - symbol: "DOT", - existentialDeposit: 10n**3n, + decimals: 12, + name: "ROC", + symbol: "ROC", + existentialDeposit: 10n ** 3n, location: null, - additional: null + additional: null, }; const assetSetupCalls = [ - api.tx.assetRegistry.registerAsset(assetMetadata, ASSET_ID), - api.tx.assetRate.create(ASSET_ID, 1000000000000000000n), // 1 on 1 - api.tx.tokens.setBalance(alice.address, ASSET_ID, 10n**12n, 0), + regionXApi.tx.assetRegistry.registerAsset(assetMetadata, RELAY_ASSET_ID), + regionXApi.tx.assetRate.create(RELAY_ASSET_ID, 1_000_000_000_000_000_000n), // 1 on 1 + regionXApi.tx.tokens.setBalance( + alice.address, + RELAY_ASSET_ID, + 10n ** 12n, + 0, + ), ]; - const batchCall = api.tx.utility.batch(assetSetupCalls); - const sudo = api.tx.sudo.sudo(batchCall); + const batchCall = regionXApi.tx.utility.batch(assetSetupCalls); + const sudoCall = regionXApi.tx.sudo.sudo(batchCall); + + await submitExtrinsic(alice, sudoCall, {}); - await submitExtrinsic(alice, sudo, {}); + 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, {}); - const remarkCall = api.tx.system.remark("0x44"); - await submitExtrinsic(alice, remarkCall, {assetId: ASSET_ID}); + // Try to pay for fees with relay chain asset. + const remarkCall = regionXApi.tx.system.remark("0x44"); + await submitExtrinsic(alice, remarkCall, { assetId: RELAY_ASSET_ID }); } module.exports = { run }; diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index d2ea3b91..9429cff1 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -79,7 +79,7 @@ pub fn session_keys(keys: AuraId) -> regionx_runtime::SessionKeys { pub fn development_config(id: u32) -> ChainSpec { // Give your base currency a unit name and decimal places let mut properties = sc_chain_spec::Properties::new(); - properties.insert("tokenSymbol".into(), "M4X".into()); + properties.insert("tokenSymbol".into(), "REGX".into()); properties.insert("tokenDecimals".into(), 12.into()); // TODO: chose an ss58Format properties.insert("ss58Format".into(), 42.into()); @@ -130,7 +130,7 @@ pub fn development_config(id: u32) -> ChainSpec ChainSpec { // Give your base currency a unit name and decimal places let mut properties = sc_chain_spec::Properties::new(); - properties.insert("tokenSymbol".into(), "M4X".into()); + properties.insert("tokenSymbol".into(), "REGX".into()); properties.insert("tokenDecimals".into(), 12.into()); // TODO: chose an ss58Format properties.insert("ss58Format".into(), 42.into()); diff --git a/runtime/regionx/Cargo.toml b/runtime/regionx/Cargo.toml index 2aa5edf7..595d5b3a 100644 --- a/runtime/regionx/Cargo.toml +++ b/runtime/regionx/Cargo.toml @@ -35,6 +35,8 @@ orml-asset-registry = { workspace = true } orml-currencies = { workspace = true } orml-tokens = { workspace = true } orml-traits = { workspace = true } +orml-unknown-tokens = { workspace = true } +orml-xcm-support = { workspace = true } # Substrate frame-benchmarking = { workspace = true, optional = true } @@ -125,6 +127,8 @@ std = [ "orml-currencies/std", "orml-tokens/std", "orml-traits/std", + "orml-unknown-tokens/std", + "orml-xcm-support/std", "pallet-aura/std", "pallet-authorship/std", "pallet-asset-rate/std", diff --git a/runtime/regionx/src/lib.rs b/runtime/regionx/src/lib.rs index b7826898..9322704a 100644 --- a/runtime/regionx/src/lib.rs +++ b/runtime/regionx/src/lib.rs @@ -441,6 +441,10 @@ impl pallet_asset_rate::Config for Runtime { type BenchmarkHelper = (); } +impl orml_unknown_tokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + impl pallet_asset_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = Tokens; @@ -709,6 +713,7 @@ construct_runtime!( Tokens: orml_tokens = 14, Currencies: orml_currencies = 15, AssetRate: pallet_asset_rate = 16, + UnknownTokens: orml_unknown_tokens = 17, // Governance Sudo: pallet_sudo = 20, diff --git a/runtime/regionx/src/xcm_config.rs b/runtime/regionx/src/xcm_config.rs index 51f55038..7d55ee28 100644 --- a/runtime/regionx/src/xcm_config.rs +++ b/runtime/regionx/src/xcm_config.rs @@ -14,25 +14,30 @@ // along with RegionX. If not, see . use super::{ - AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, AssetId, Balance, Balances, Currencies, ParachainInfo, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, UnknownTokens, + WeightToFee, XcmpQueue, }; use frame_support::{ match_types, parameter_types, traits::{ConstU32, Everything, Nothing}, + PalletId, }; use frame_system::EnsureRoot; +use orml_xcm_support::{DepositToAlternative, IsNativeConcrete, MultiCurrencyAdapter}; 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 sp_runtime::traits::{AccountIdConversion, Convert}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, - FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, + FrameTransactionalProcessor, NativeAsset, ParentIsPreset, RelayChainAsNative, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::XcmExecutor; @@ -55,20 +60,54 @@ pub type LocationToAccountId = ( AccountId32Aliases, ); +parameter_types! { + // The account which receives multi-currency tokens from failed attempts to deposit them + pub Alternative: AccountId = PalletId(*b"xcm/alte").into_account_truncating(); +} + /// Means for transacting assets on this chain. -pub type LocalAssetTransactor = FungibleAdapter< - // Use this currency: - Balances, - // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, - // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): +pub type FungiblesAssetTransactor = MultiCurrencyAdapter< + Currencies, + UnknownTokens, + IsNativeConcrete, AccountId, - // We don't track any teleports. - (), + LocationToAccountId, + AssetId, + AssetIdConverter, + DepositToAlternative, >; +pub struct AssetIdConverter; +impl Convert> for AssetIdConverter { + fn convert(id: AssetId) -> Option { + match id { + RELAY_CHAIN_ASSET_ID => Some(MultiLocation::parent()), + REGX_ASSET_ID => Some(MultiLocation::here()), + _ => None, + } + } +} + +impl Convert> for AssetIdConverter { + fn convert(location: MultiLocation) -> Option { + match location { + MultiLocation { parents: 1, interior: Here } => Some(RELAY_CHAIN_ASSET_ID), + MultiLocation { parents: 0, interior: Here } => Some(REGX_ASSET_ID), + _ => None, + } + } +} + +impl Convert> for AssetIdConverter { + fn convert(asset: MultiAsset) -> Option { + if let MultiAsset { id: Concrete(location), .. } = asset { + Self::convert(location) + } else { + None + } + } +} + /// 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. @@ -127,7 +166,7 @@ impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; // How to withdraw and deposit an asset. - type AssetTransactor = LocalAssetTransactor; + type AssetTransactor = FungiblesAssetTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; type IsReserve = NativeAsset; type IsTeleporter = (); // Teleporting is disabled. diff --git a/zombienet_tests/0001-block-production.zndsl b/zombienet_tests/0001-block-production.zndsl index 2153b9d7..30f2bec5 100644 --- a/zombienet_tests/0001-block-production.zndsl +++ b/zombienet_tests/0001-block-production.zndsl @@ -1,5 +1,5 @@ Description: Block production smoke test -Network: ./0001-smoke-test.toml +Network: ./0001-block-production.toml Creds: config alice: is up diff --git a/zombienet_tests/0003-custom-fee-payment.toml b/zombienet_tests/0003-custom-fee-payment.toml index c74fbef6..c1ad77e6 100644 --- a/zombienet_tests/0003-custom-fee-payment.toml +++ b/zombienet_tests/0003-custom-fee-payment.toml @@ -6,11 +6,11 @@ chain = "rococo-local" command = "polkadot" [[relaychain.nodes]] - name = "alice" + name = "rococo-validator01" validator = true [[relaychain.nodes]] - name = "bob" + name = "rococo-validator02" validator = true [[parachains]] diff --git a/zombienet_tests/0003-custom-fee-payment.zndsl b/zombienet_tests/0003-custom-fee-payment.zndsl index 36561db3..51b8d605 100644 --- a/zombienet_tests/0003-custom-fee-payment.zndsl +++ b/zombienet_tests/0003-custom-fee-payment.zndsl @@ -2,9 +2,9 @@ Description: Native currency fee payment Network: ./0003-custom-fee-payment.toml Creds: config -alice: is up -bob: is up +rococo-validator01: is up +rococo-validator02: is up -alice: parachain 2000 is registered within 225 seconds +rococo-validator01: parachain 2000 is registered within 225 seconds regionx-collator01: js-script ../e2e_tests/custom-fee-payment.js return is 0 within 400 seconds From 6c6f69e2db85ae890e13541a79afe167fdcf7b80 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Sat, 27 Apr 2024 21:31:44 +0200 Subject: [PATCH 3/8] Governance delegated to relay chain token holders (#102) * MultiCurrency Asset Transactor * fee payment with rc token * prettier * handle unknown tokens * fmt * Governance * compiles * tests | wip * tests working * fmt * fix version check * small fixes prior merge --- .github/workflows/dependencies.yml | 2 +- Cargo.lock | 7 +- Cargo.toml | 4 +- README.md | 2 +- e2e_tests/common.js | 31 ++++++++- e2e_tests/custom-fee-payment.js | 28 +------- e2e_tests/governance.js | 52 +++++++++++++++ runtime/regionx/Cargo.toml | 9 +++ runtime/regionx/src/governance/mod.rs | 64 +++++++++++++++++++ runtime/regionx/src/governance/tracks.rs | 61 ++++++++++++++++++ runtime/regionx/src/impls.rs | 15 +++++ runtime/regionx/src/lib.rs | 16 ++++- zombienet_tests/0003-custom-fee-payment.toml | 2 - zombienet_tests/0003-custom-fee-payment.zndsl | 2 +- zombienet_tests/0004-governance.toml | 23 +++++++ zombienet_tests/0004-governance.zndsl | 10 +++ 16 files changed, 291 insertions(+), 37 deletions(-) create mode 100644 e2e_tests/governance.js create mode 100644 runtime/regionx/src/governance/mod.rs create mode 100644 runtime/regionx/src/governance/tracks.rs create mode 100644 zombienet_tests/0004-governance.toml create mode 100644 zombienet_tests/0004-governance.zndsl diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index cb1af387..309bce68 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -22,7 +22,7 @@ jobs: - uses: ./.github/actions/setup - name: Install Rust - run: cargo install psvm@0.1.0 + run: cargo install --git https://github.com/paritytech/psvm --rev a3ecef700e4c1429c2d01e265a145654ceb3cc49 psvm - name: Check Dependency Versions run: | chmod +x ./scripts/check-dependency-versions.sh diff --git a/Cargo.lock b/Cargo.lock index 8e7052c9..e5ef666c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6299,15 +6299,16 @@ dependencies = [ [[package]] name = "pallet-collator-selection" -version = "9.0.0" +version = "9.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4199122c135e161d2e2f4cbc9339c54a11ac4b11e0beb67e53b49a3c90d566b" +checksum = "05cc67e8233b748a0c0b1ecc2cbecfc6deb08be633fedba9c3d6b1ade6c2a036" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", "pallet-authorship", + "pallet-balances", "pallet-session", "parity-scale-codec", "rand", @@ -9451,12 +9452,14 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-conviction-voting", "pallet-ismp", "pallet-ismp-runtime-api", "pallet-message-queue", "pallet-multisig", "pallet-preimage", "pallet-proxy", + "pallet-referenda", "pallet-regions", "pallet-scheduler", "pallet-session", diff --git a/Cargo.toml b/Cargo.toml index a0a01304..112f3970 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,12 +42,14 @@ pallet-aura = { version = "27.0.0", default-features = false } pallet-authorship = { version = "28.0.0", default-features = false } pallet-balances = { version = "28.0.0", default-features = false } pallet-broker = { version = "0.6.0", default-features = false } +pallet-conviction-voting = { version = "28.0.0", default-features = false } pallet-session = { version = "28.0.0", default-features = false } pallet-sudo = { version = "28.0.0", default-features = false } pallet-timestamp = { version = "27.0.0", default-features = false } pallet-transaction-payment = { version = "28.0.0", default-features = false } pallet-asset-rate = { version = "7.0.0", default-features = false } pallet-asset-tx-payment = { version = "28.0.0", default-features = false } +pallet-referenda = { version = "28.0.0", default-features = false } pallet-transaction-payment-rpc-runtime-api = { version = "28.0.0", default-features = false } pallet-message-queue = { version = "31.0.0", default-features = false } pallet-multisig = { version = "28.0.0", default-features = false } @@ -87,7 +89,7 @@ cumulus-pallet-xcmp-queue = { version = "0.7.0", default-features = false } cumulus-primitives-core = { version = "0.7.0", default-features = false } cumulus-primitives-timestamp = { version = "0.7.0", default-features = false } cumulus-primitives-utility = { version = "0.7.3", default-features = false } -pallet-collator-selection = { version = "9.0.2", default-features = false } +pallet-collator-selection = { version = "9.0.0", default-features = false } parachain-info = { version = "0.7.0", package = "staging-parachain-info", default-features = false } parachains-common = { version = "7.0.0", default-features = false } sp-timestamp = { version = "26.0.0", default-features = false } diff --git a/README.md b/README.md index 42604cb2..cd0e92c5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ 2. Build the `regionx-node` by running: ``` - cargo build --release + cargo build --release --features fast-runtime ``` 3. Get the polkadot binary: diff --git a/e2e_tests/common.js b/e2e_tests/common.js index 590a78f7..60b7a576 100644 --- a/e2e_tests/common.js +++ b/e2e_tests/common.js @@ -1,3 +1,5 @@ +const RELAY_ASSET_ID = 1; + async function submitExtrinsic(signer, call, options) { return new Promise(async (resolve, reject) => { const unsub = await call.signAndSend(signer, options, (result) => { @@ -21,4 +23,31 @@ async function submitExtrinsic(signer, call, options) { }); } -module.exports = { submitExtrinsic } +async function setupRelayAsset(api, signer) { + const assetMetadata = { + decimals: 12, + name: "ROC", + symbol: "ROC", + existentialDeposit: 10n ** 3n, + location: null, + additional: null, + }; + + const assetSetupCalls = [ + api.tx.assetRegistry.registerAsset(assetMetadata, RELAY_ASSET_ID), + api.tx.assetRate.create(RELAY_ASSET_ID, 1_000_000_000_000_000_000n), // 1 on 1 + api.tx.tokens.setBalance( + signer.address, + RELAY_ASSET_ID, + 10n ** 12n, + 0, + ), + ]; + + const batchCall = api.tx.utility.batch(assetSetupCalls); + const sudoCall = api.tx.sudo.sudo(batchCall); + + await submitExtrinsic(signer, sudoCall, {}); +} + +module.exports = { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } diff --git a/e2e_tests/custom-fee-payment.js b/e2e_tests/custom-fee-payment.js index 9e1c058b..ab0db92c 100644 --- a/e2e_tests/custom-fee-payment.js +++ b/e2e_tests/custom-fee-payment.js @@ -1,7 +1,5 @@ const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); -const { submitExtrinsic } = require("./common"); - -const RELAY_ASSET_ID = 1; +const { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } = require("./common"); async function run(nodeName, networkInfo, _jsArgs) { const { wsUri: regionXUri } = networkInfo.nodesByName[nodeName]; @@ -30,29 +28,7 @@ async function run(nodeName, networkInfo, _jsArgs) { const setXcmVersion = rococoApi.tx.xcmPallet.forceDefaultXcmVersion([3]); await submitExtrinsic(alice, rococoApi.tx.sudo.sudo(setXcmVersion), {}); - const assetMetadata = { - decimals: 12, - name: "ROC", - symbol: "ROC", - existentialDeposit: 10n ** 3n, - location: null, - additional: null, - }; - - const assetSetupCalls = [ - regionXApi.tx.assetRegistry.registerAsset(assetMetadata, RELAY_ASSET_ID), - regionXApi.tx.assetRate.create(RELAY_ASSET_ID, 1_000_000_000_000_000_000n), // 1 on 1 - regionXApi.tx.tokens.setBalance( - alice.address, - RELAY_ASSET_ID, - 10n ** 12n, - 0, - ), - ]; - const batchCall = regionXApi.tx.utility.batch(assetSetupCalls); - const sudoCall = regionXApi.tx.sudo.sudo(batchCall); - - await submitExtrinsic(alice, sudoCall, {}); + await setupRelayAsset(regionXApi, alice); const receiverKeypair = new Keyring(); receiverKeypair.addFromAddress(alice.address); diff --git a/e2e_tests/governance.js b/e2e_tests/governance.js new file mode 100644 index 00000000..072cc953 --- /dev/null +++ b/e2e_tests/governance.js @@ -0,0 +1,52 @@ +const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); +const { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } = require("./common"); + +const PREIMAGE_HASH = "0xb8375f7ca0c64a384f2dd643a0d520977f3aae06e64afb8c960891eee5147bd1"; + +async function run(nodeName, networkInfo, _jsArgs) { + const { wsUri } = networkInfo.nodesByName[nodeName]; + const api = await ApiPromise.create({ + provider: new WsProvider(wsUri), + signedExtensions: { + ChargeAssetTxPayment: { + extrinsic: { + tip: "Compact", + assetId: "Option", + }, + payload: {}, + }, + }, + }); + + // account to submit tx + const keyring = new Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + const anna = keyring.addFromUri("//Anna"); + + await setupRelayAsset(api, alice); + + const giveBalanceCall = api.tx.tokens.setBalance(anna.address, RELAY_ASSET_ID, 10n ** 18n, 0); + await submitExtrinsic(alice, api.tx.sudo.sudo(giveBalanceCall), {}); + + const remarkCallBytes = api.tx.system.remark("hey").toU8a(); + await submitExtrinsic(alice, api.tx.preimage.notePreimage(remarkCallBytes), {}); + + const submitProposal = api.tx.referenda.submit( + { system: "Root" }, + { Lookup: { hash: PREIMAGE_HASH, len: remarkCallBytes.length } }, + { After: 5 }, + ); + await submitExtrinsic(anna, submitProposal, { assetId: RELAY_ASSET_ID }); + + const placeDeposit = api.tx.referenda.placeDecisionDeposit(0); + await submitExtrinsic(anna, placeDeposit, { assetId: RELAY_ASSET_ID }); + + const voteCall = api.tx.convictionVoting.vote(0, { + // Voting with relay chain tokens. We know this is true; otherwise, this call + // would fail, given that Anna doesn't have 10^16 RegionX tokens. + Standard: { vote: { aye: true, conviction: "None" }, balance: 10n ** 16n }, + }); + await submitExtrinsic(anna, voteCall, { assetId: RELAY_ASSET_ID }); +} + +module.exports = { run }; diff --git a/runtime/regionx/Cargo.toml b/runtime/regionx/Cargo.toml index 595d5b3a..605c5493 100644 --- a/runtime/regionx/Cargo.toml +++ b/runtime/regionx/Cargo.toml @@ -51,6 +51,8 @@ pallet-authorship = { workspace = true } pallet-asset-rate = { workspace = true } pallet-asset-tx-payment = { workspace = true } pallet-balances = { workspace = true } +pallet-conviction-voting = { workspace = true } +pallet-referenda = { workspace = true } pallet-message-queue = { workspace = true } pallet-multisig = { workspace = true } pallet-proxy = { workspace = true } @@ -134,8 +136,10 @@ std = [ "pallet-asset-rate/std", "pallet-asset-tx-payment/std", "pallet-balances/std", + "pallet-conviction-voting/std", "pallet-collator-selection/std", "pallet-message-queue/std", + "pallet-referenda/std", "pallet-regions/std", "regionx-primitives/std", "pallet-multisig/std", @@ -189,6 +193,7 @@ runtime-benchmarks = [ "pallet-asset-rate/runtime-benchmarks", "pallet-asset-tx-payment/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-conviction-voting/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", @@ -228,6 +233,7 @@ try-runtime = [ "pallet-asset-rate/try-runtime", "pallet-asset-tx-payment/try-runtime", "pallet-balances/try-runtime", + "pallet-conviction-voting/try-runtime", "pallet-collator-selection/try-runtime", "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", @@ -246,4 +252,7 @@ try-runtime = [ "sp-runtime/try-runtime", ] +# Reducing waiting times for governance or other +fast-runtime = [] + experimental = ["pallet-aura/experimental"] diff --git a/runtime/regionx/src/governance/mod.rs b/runtime/regionx/src/governance/mod.rs new file mode 100644 index 00000000..2e8aa9d2 --- /dev/null +++ b/runtime/regionx/src/governance/mod.rs @@ -0,0 +1,64 @@ +// This file is part of RegionX. +// +// RegionX 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. +// +// RegionX 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 RegionX. If not, see . + +use crate::*; + +mod tracks; +use tracks::*; + +use polkadot_runtime_common::prod_or_fast; + +parameter_types! { + pub const VoteLockingPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1); +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type Currency = RelayChainCurrency; + type VoteLockingPeriod = VoteLockingPeriod; + type MaxVotes = ConstU32<512>; + type MaxTurnout = frame_support::traits::tokens::currency::ActiveIssuanceOf< + RelayChainCurrency, + Self::AccountId, + >; + type Polls = Referenda; +} + +parameter_types! { + pub const AlarmInterval: BlockNumber = 1; + pub const SubmissionDeposit: Balance = 5 * KSM; + pub const UndecidingTimeout: BlockNumber = 14 * DAYS; +} + +impl pallet_referenda::Config for Runtime { + type WeightInfo = (); + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = RelayChainCurrency; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = EnsureRoot; // TODO: Or Technical fellowship + type KillOrigin = EnsureRoot; // TODO: Or Technical fellowship + type Slash = (); // TODO: treasury + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = SubmissionDeposit; + type MaxQueued = ConstU32<100>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = TracksInfo; + type Preimages = Preimage; +} diff --git a/runtime/regionx/src/governance/tracks.rs b/runtime/regionx/src/governance/tracks.rs new file mode 100644 index 00000000..f71063b1 --- /dev/null +++ b/runtime/regionx/src/governance/tracks.rs @@ -0,0 +1,61 @@ +// This file is part of RegionX. +// +// RegionX 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. +// +// RegionX 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 RegionX. If not, see . + +use crate::*; + +use pallet_referenda::Curve; + +const fn percent(x: i32) -> sp_runtime::FixedI64 { + sp_runtime::FixedI64::from_rational(x as u128, 100) +} + +const APP_ROOT: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_ROOT: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); + +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 1] = [( + 0, + pallet_referenda::TrackInfo { + name: "root", + max_deciding: 1, + decision_deposit: 50 * KSM, // TODO: adjust + prepare_period: 2 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_ROOT, + min_support: SUP_ROOT, + }, +)]; + +pub struct TracksInfo; +impl pallet_referenda::TracksInfo for TracksInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &TRACKS_DATA[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> Result { + if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { + match system_origin { + frame_system::RawOrigin::Root => Ok(0), + _ => Err(()), + } + } else { + // Root is the only avaialable origin for relay chain asset holders. + Err(()) + } + } +} +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); diff --git a/runtime/regionx/src/impls.rs b/runtime/regionx/src/impls.rs index 06ceb026..1e6d6b69 100644 --- a/runtime/regionx/src/impls.rs +++ b/runtime/regionx/src/impls.rs @@ -1,3 +1,18 @@ +// This file is part of RegionX. +// +// RegionX 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. +// +// RegionX 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 RegionX. If not, see . + use crate::{AccountId, AssetId, AssetRegistry, Authorship, Balance, Runtime, RuntimeCall, Tokens}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::{ diff --git a/runtime/regionx/src/lib.rs b/runtime/regionx/src/lib.rs index 9322704a..20aa6840 100644 --- a/runtime/regionx/src/lib.rs +++ b/runtime/regionx/src/lib.rs @@ -26,6 +26,7 @@ extern crate alloc; mod weights; pub mod xcm_config; +mod governance; mod impls; mod ismp; @@ -76,6 +77,7 @@ use frame_system::{ EnsureRoot, Phase, }; use orml_currencies::BasicCurrencyAdapter; +use orml_tokens::CurrencyAdapter; use pallet_asset_tx_payment::FungiblesAdapter; use pallet_ismp::{ dispatcher::Dispatcher, @@ -101,7 +103,7 @@ use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use xcm::latest::prelude::BodyId; use regionx_primitives::{ - assets::{AssetId, CustomMetadata, REGX_ASSET_ID}, + assets::{AssetId, CustomMetadata, REGX_ASSET_ID, RELAY_CHAIN_ASSET_ID}, AccountId, Address, Amount, Balance, BlockNumber, Hash, Header, Nonce, Signature, }; @@ -139,6 +141,9 @@ pub type Executive = frame_executive::Executive< AllPalletsWithSystem, >; +/// The relay chain currency on the RegionX parachain. +pub type RelayChainCurrency = CurrencyAdapter>; + /// Handles converting a weight scalar to a fee value, based on the scale and granularity of the /// node's balance type. /// @@ -206,6 +211,10 @@ pub const REGX: Balance = 1_000_000_000_000; pub const MILLIREGX: Balance = 1_000_000_000; pub const MICROREGX: Balance = 1_000_000; +pub const KSM: Balance = 1_000_000_000_000; +pub const MILLI_KSM: Balance = 1_000_000_000; +pub const MICRO_KSM: Balance = 1_000_000; + pub const fn deposit(items: u32, bytes: u32) -> Balance { // TODO: ensure this is a sensible value. items as Balance * REGX + (bytes as Balance) * MILLIREGX @@ -415,6 +424,7 @@ impl orml_asset_registry::Config for Runtime { } parameter_types! { + // TODO: set to a reasonable value. /// Relay Chain `TransactionByteFee` / 10 pub const TransactionByteFee: Balance = 10 * MICROREGX; } @@ -716,7 +726,9 @@ construct_runtime!( UnknownTokens: orml_unknown_tokens = 17, // Governance - Sudo: pallet_sudo = 20, + Sudo: pallet_sudo = 20, // TODO: leave this only for testnets + Referenda: pallet_referenda = 21, + ConvictionVoting: pallet_conviction_voting = 22, // Collator support. The order of these 4 are important and shall not change. Authorship: pallet_authorship = 30, diff --git a/zombienet_tests/0003-custom-fee-payment.toml b/zombienet_tests/0003-custom-fee-payment.toml index c1ad77e6..635f5419 100644 --- a/zombienet_tests/0003-custom-fee-payment.toml +++ b/zombienet_tests/0003-custom-fee-payment.toml @@ -21,5 +21,3 @@ addToGenesis = false name = "regionx-collator01" command = "regionx-node" args = [ "-lruntime=debug,parachain=trace" ] - - diff --git a/zombienet_tests/0003-custom-fee-payment.zndsl b/zombienet_tests/0003-custom-fee-payment.zndsl index 51b8d605..4625233d 100644 --- a/zombienet_tests/0003-custom-fee-payment.zndsl +++ b/zombienet_tests/0003-custom-fee-payment.zndsl @@ -1,4 +1,4 @@ -Description: Native currency fee payment +Description: Custom currency fee payment Network: ./0003-custom-fee-payment.toml Creds: config diff --git a/zombienet_tests/0004-governance.toml b/zombienet_tests/0004-governance.toml new file mode 100644 index 00000000..635f5419 --- /dev/null +++ b/zombienet_tests/0004-governance.toml @@ -0,0 +1,23 @@ +[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 = 2000 +addToGenesis = false + + [parachains.collator] + name = "regionx-collator01" + command = "regionx-node" + args = [ "-lruntime=debug,parachain=trace" ] diff --git a/zombienet_tests/0004-governance.zndsl b/zombienet_tests/0004-governance.zndsl new file mode 100644 index 00000000..8e6a6175 --- /dev/null +++ b/zombienet_tests/0004-governance.zndsl @@ -0,0 +1,10 @@ +Description: Native currency fee payment +Network: ./0004-governance.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/governance.js return is 0 within 400 seconds From a4a788671639d118b3f4aea66ff05ea7bca84b83 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Mon, 29 Apr 2024 09:17:31 +0200 Subject: [PATCH 4/8] General council and technical committee (#104) * Technical committee * membership * general council * whitelisted caller | wip * add whitelist pallet * add spender tracks * cancel and kill origin * fix --- Cargo.lock | 3 + Cargo.toml | 3 + runtime/regionx/Cargo.toml | 14 ++- runtime/regionx/src/governance/mod.rs | 95 ++++++++++++++++++- runtime/regionx/src/governance/origins.rs | 107 ++++++++++++++++++++++ runtime/regionx/src/governance/tracks.rs | 58 ++++++++---- runtime/regionx/src/lib.rs | 8 ++ 7 files changed, 266 insertions(+), 22 deletions(-) create mode 100644 runtime/regionx/src/governance/origins.rs diff --git a/Cargo.lock b/Cargo.lock index e5ef666c..40132f5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9452,9 +9452,11 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-collective", "pallet-conviction-voting", "pallet-ismp", "pallet-ismp-runtime-api", + "pallet-membership", "pallet-message-queue", "pallet-multisig", "pallet-preimage", @@ -9468,6 +9470,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-utility", + "pallet-whitelist", "pallet-xcm", "parachains-common", "parity-scale-codec", diff --git a/Cargo.toml b/Cargo.toml index 112f3970..2e3e76e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ pallet-aura = { version = "27.0.0", default-features = false } pallet-authorship = { version = "28.0.0", default-features = false } pallet-balances = { version = "28.0.0", default-features = false } pallet-broker = { version = "0.6.0", default-features = false } +pallet-collective = { version = "28.0.0", default-features = false } pallet-conviction-voting = { version = "28.0.0", default-features = false } pallet-session = { version = "28.0.0", default-features = false } pallet-sudo = { version = "28.0.0", default-features = false } @@ -51,12 +52,14 @@ pallet-asset-rate = { version = "7.0.0", default-features = false } pallet-asset-tx-payment = { version = "28.0.0", default-features = false } pallet-referenda = { version = "28.0.0", default-features = false } pallet-transaction-payment-rpc-runtime-api = { version = "28.0.0", default-features = false } +pallet-membership = { version = "28.0.0", default-features = false } pallet-message-queue = { version = "31.0.0", default-features = false } pallet-multisig = { version = "28.0.0", default-features = false } pallet-proxy = { version = "28.0.0", default-features = false } pallet-preimage = { version = "28.0.0", default-features = false } pallet-scheduler = { version = "29.0.0", default-features = false } pallet-utility = { version = "28.0.0", default-features = false } +pallet-whitelist = { version = "27.0.0", default-features = false } sp-api = { version = "26.0.0", default-features = false } sp-blockchain = { version = "28.0.0", default-features = false } sp-io = { version = "30.0.0", default-features = false } diff --git a/runtime/regionx/Cargo.toml b/runtime/regionx/Cargo.toml index 605c5493..33813018 100644 --- a/runtime/regionx/Cargo.toml +++ b/runtime/regionx/Cargo.toml @@ -51,8 +51,10 @@ pallet-authorship = { workspace = true } pallet-asset-rate = { workspace = true } pallet-asset-tx-payment = { workspace = true } pallet-balances = { workspace = true } +pallet-collective = { workspace = true } pallet-conviction-voting = { workspace = true } pallet-referenda = { workspace = true } +pallet-membership = { workspace = true } pallet-message-queue = { workspace = true } pallet-multisig = { workspace = true } pallet-proxy = { workspace = true } @@ -64,6 +66,7 @@ pallet-timestamp = { workspace = true } pallet-transaction-payment = { workspace = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true } pallet-utility = { workspace = true } +pallet-whitelist = { workspace = true } sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } @@ -136,12 +139,14 @@ std = [ "pallet-asset-rate/std", "pallet-asset-tx-payment/std", "pallet-balances/std", + "pallet-collective/std", "pallet-conviction-voting/std", "pallet-collator-selection/std", - "pallet-message-queue/std", "pallet-referenda/std", "pallet-regions/std", "regionx-primitives/std", + "pallet-membership/std", + "pallet-message-queue/std", "pallet-multisig/std", "pallet-proxy/std", "pallet-preimage/std", @@ -153,6 +158,7 @@ std = [ "pallet-transaction-payment/std", "pallet-utility/std", "pallet-xcm/std", + "pallet-whitelist/std", "parachain-info/std", "parachains-common/std", "polkadot-parachain-primitives/std", @@ -193,8 +199,10 @@ runtime-benchmarks = [ "pallet-asset-rate/runtime-benchmarks", "pallet-asset-tx-payment/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-collective/runtime-benchmarks", "pallet-conviction-voting/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", + "pallet-membership/std", "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", @@ -205,6 +213,7 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", + "pallet-whitelist/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", @@ -233,8 +242,10 @@ try-runtime = [ "pallet-asset-rate/try-runtime", "pallet-asset-tx-payment/try-runtime", "pallet-balances/try-runtime", + "pallet-collective/try-runtime", "pallet-conviction-voting/try-runtime", "pallet-collator-selection/try-runtime", + "pallet-membership/std", "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", "pallet-proxy/try-runtime", @@ -247,6 +258,7 @@ try-runtime = [ "pallet-transaction-payment/try-runtime", "pallet-utility/try-runtime", "pallet-xcm/try-runtime", + "pallet-whitelist/try-runtime", "parachain-info/try-runtime", "polkadot-runtime-common/try-runtime", "sp-runtime/try-runtime", diff --git a/runtime/regionx/src/governance/mod.rs b/runtime/regionx/src/governance/mod.rs index 2e8aa9d2..57f9ff26 100644 --- a/runtime/regionx/src/governance/mod.rs +++ b/runtime/regionx/src/governance/mod.rs @@ -13,13 +13,26 @@ // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . -use crate::*; +use super::*; +mod origins; +pub use origins::{pallet_custom_origins, WhitelistedCaller}; mod tracks; -use tracks::*; +pub use tracks::*; use polkadot_runtime_common::prod_or_fast; +pub type GeneralCouncilInstance = pallet_collective::Instance1; +pub type TechnicalCommitteeInstance = pallet_collective::Instance2; + +pub type GeneralCouncilMembershipInstance = pallet_membership::Instance1; +pub type TechnicalCommitteeMembershipInstance = pallet_membership::Instance2; + +type EnsureTwoThirdGeneralCouncil = + pallet_collective::EnsureProportionAtLeast; +type EnsureTwoThirdTechnicalCommittee = + pallet_collective::EnsureProportionAtLeast; + parameter_types! { pub const VoteLockingPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1); } @@ -50,15 +63,87 @@ impl pallet_referenda::Config for Runtime { type Scheduler = Scheduler; type Currency = RelayChainCurrency; type SubmitOrigin = frame_system::EnsureSigned; - type CancelOrigin = EnsureRoot; // TODO: Or Technical fellowship - type KillOrigin = EnsureRoot; // TODO: Or Technical fellowship + type CancelOrigin = + EitherOfDiverse; + type KillOrigin = + EitherOfDiverse; type Slash = (); // TODO: treasury type Votes = pallet_conviction_voting::VotesOf; type Tally = pallet_conviction_voting::TallyOf; type SubmissionDeposit = SubmissionDeposit; - type MaxQueued = ConstU32<100>; + type MaxQueued = ConstU32<50>; type UndecidingTimeout = UndecidingTimeout; type AlarmInterval = AlarmInterval; type Tracks = TracksInfo; type Preimages = Preimage; } + +parameter_types! { + pub const MotionDuration: BlockNumber = 3 * DAYS; + pub const MaxMembers: u32 = 30; + pub const MaxProposals: u32 = 10; + pub MaxProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type MotionDuration = MotionDuration; + type MaxProposals = MaxProposals; + type MaxMembers = MaxMembers; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type SetMembersOrigin = EnsureTwoThirdGeneralCouncil; + type WeightInfo = (); + type MaxProposalWeight = MaxProposalWeight; +} + +impl pallet_collective::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type MotionDuration = MotionDuration; + type MaxProposals = MaxProposals; + type MaxMembers = MaxMembers; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type SetMembersOrigin = EnsureTwoThirdGeneralCouncil; + type WeightInfo = (); + type MaxProposalWeight = MaxProposalWeight; +} + +impl pallet_membership::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AddOrigin = EnsureTwoThirdGeneralCouncil; + type RemoveOrigin = EnsureTwoThirdGeneralCouncil; + type SwapOrigin = EnsureTwoThirdGeneralCouncil; + type ResetOrigin = EnsureTwoThirdGeneralCouncil; + type PrimeOrigin = EnsureTwoThirdGeneralCouncil; + type MembershipInitialized = GeneralCouncil; + type MembershipChanged = GeneralCouncil; + type MaxMembers = MaxMembers; + type WeightInfo = (); +} + +impl pallet_membership::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AddOrigin = EnsureTwoThirdGeneralCouncil; + type RemoveOrigin = EnsureTwoThirdGeneralCouncil; + type SwapOrigin = EnsureTwoThirdGeneralCouncil; + type ResetOrigin = EnsureTwoThirdGeneralCouncil; + type PrimeOrigin = EnsureTwoThirdGeneralCouncil; + type MembershipInitialized = TechnicalCommittee; + type MembershipChanged = TechnicalCommittee; + type MaxMembers = MaxMembers; + type WeightInfo = (); +} + +impl pallet_custom_origins::Config for Runtime {} + +impl pallet_whitelist::Config for Runtime { + type WeightInfo = (); + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type WhitelistOrigin = EnsureTwoThirdTechnicalCommittee; + type DispatchWhitelistedOrigin = WhitelistedCaller; + type Preimages = Preimage; +} diff --git a/runtime/regionx/src/governance/origins.rs b/runtime/regionx/src/governance/origins.rs new file mode 100644 index 00000000..7eb0c321 --- /dev/null +++ b/runtime/regionx/src/governance/origins.rs @@ -0,0 +1,107 @@ +pub use pallet_custom_origins::*; + +// TODO: investigate warning +#[allow(unused_imports)] +#[frame_support::pallet] +pub mod pallet_custom_origins { + use crate::{Balance, REGX}; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[derive(PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, TypeInfo, RuntimeDebug)] + #[pallet::origin] + pub enum Origin { + /// Origin able to dispatch a whitelisted call. + WhitelistedCaller, + /// Origin able to spend up to 500 REGX from the treasury at once. + SmallTipper, + /// Origin able to spend up to 2,000 REGX from the treasury at once. + BigTipper, + /// Origin able to spend up to 50,000 REGX from the treasury at once. + SmallSpender, + /// Origin able to spend up to 200,000 REGX from the treasury at once. + MediumSpender, + /// Origin able to spend up to 500,000 REGX from the treasury at once. + BigSpender, + } + + macro_rules! decl_unit_ensures { + ( $name:ident: $success_type:ty = $success:expr ) => { + pub struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + Origin::$name => Ok($success), + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(Origin::$name)) + } + } + }; + ( $name:ident ) => { decl_unit_ensures! { $name : () = () } }; + ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => { + decl_unit_ensures! { $name: $success_type = $success } + decl_unit_ensures! { $( $rest )* } + }; + ( $name:ident, $( $rest:tt )* ) => { + decl_unit_ensures! { $name } + decl_unit_ensures! { $( $rest )* } + }; + () => {} + } + decl_unit_ensures!(WhitelistedCaller); + + macro_rules! decl_ensure { + ( + $vis:vis type $name:ident: EnsureOrigin { + $( $item:ident = $success:expr, )* + } + ) => { + $vis struct $name; + impl> + From> + EnsureOrigin for $name + { + type Success = $success_type; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + $( + Origin::$item => Ok($success), + )* + r => Err(O::from(r)), + }) + } + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + // By convention the more privileged origins go later, so for greatest chance + // of success, we want the last one. + let _result: Result = Err(()); + $( + let _result: Result = Ok(O::from(Origin::$item)); + )* + _result + } + } + } + } + + decl_ensure! { + pub type Spender: EnsureOrigin { + SmallTipper = 500 * REGX, + BigTipper = 2000 * REGX, + SmallSpender = 50_000 * REGX, + MediumSpender = 100_000 * REGX, + BigSpender = 500_000 * REGX, + } + } +} diff --git a/runtime/regionx/src/governance/tracks.rs b/runtime/regionx/src/governance/tracks.rs index f71063b1..74196a63 100644 --- a/runtime/regionx/src/governance/tracks.rs +++ b/runtime/regionx/src/governance/tracks.rs @@ -13,31 +13,52 @@ // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . -use crate::*; - +use super::*; use pallet_referenda::Curve; const fn percent(x: i32) -> sp_runtime::FixedI64 { sp_runtime::FixedI64::from_rational(x as u128, 100) } +// Same curve as on Polkadot. const APP_ROOT: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); const SUP_ROOT: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); +// Same curve as on Polkadot. +const APP_WHITELISTED_CALLER: Curve = + Curve::make_reciprocal(16, 28 * 24, percent(96), percent(50), percent(100)); +const SUP_WHITELISTED_CALLER: Curve = + Curve::make_reciprocal(1, 28, percent(20), percent(5), percent(50)); -const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 1] = [( - 0, - pallet_referenda::TrackInfo { - name: "root", - max_deciding: 1, - decision_deposit: 50 * KSM, // TODO: adjust - prepare_period: 2 * HOURS, - decision_period: 14 * DAYS, - confirm_period: 24 * HOURS, - min_enactment_period: 24 * HOURS, - min_approval: APP_ROOT, - min_support: SUP_ROOT, - }, -)]; +const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 2] = [ + ( + 0, + pallet_referenda::TrackInfo { + name: "root", + max_deciding: 1, + decision_deposit: 200 * KSM, + prepare_period: 2 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_ROOT, + min_support: SUP_ROOT, + }, + ), + ( + 1, + pallet_referenda::TrackInfo { + name: "whitelisted_caller", + max_deciding: 50, + decision_deposit: 50 * KSM, + prepare_period: 30 * MINUTES, + decision_period: 14 * DAYS, + confirm_period: 30 * MINUTES, + min_enactment_period: 30 * MINUTES, + min_approval: APP_WHITELISTED_CALLER, + min_support: SUP_WHITELISTED_CALLER, + }, + ), +]; pub struct TracksInfo; impl pallet_referenda::TracksInfo for TracksInfo { @@ -52,6 +73,11 @@ impl pallet_referenda::TracksInfo for TracksInfo { frame_system::RawOrigin::Root => Ok(0), _ => Err(()), } + } else if let Ok(custom_origin) = origins::Origin::try_from(id.clone()) { + match custom_origin { + origins::Origin::WhitelistedCaller => Ok(1), + _ => Err(()), + } } else { // Root is the only avaialable origin for relay chain asset holders. Err(()) diff --git a/runtime/regionx/src/lib.rs b/runtime/regionx/src/lib.rs index 20aa6840..951a5d40 100644 --- a/runtime/regionx/src/lib.rs +++ b/runtime/regionx/src/lib.rs @@ -27,6 +27,8 @@ mod weights; pub mod xcm_config; mod governance; +use governance::pallet_custom_origins; + mod impls; mod ismp; @@ -729,6 +731,12 @@ construct_runtime!( Sudo: pallet_sudo = 20, // TODO: leave this only for testnets Referenda: pallet_referenda = 21, ConvictionVoting: pallet_conviction_voting = 22, + GeneralCouncil: pallet_collective:: = 23, + TechnicalCommittee: pallet_collective:: = 24, + GeneralCouncilMembership: pallet_membership:: = 25, + TechnicalCommitteeMembership: pallet_membership:: = 26, + Origins: pallet_custom_origins = 27, + Whitelist: pallet_whitelist = 28, // Collator support. The order of these 4 are important and shall not change. Authorship: pallet_authorship = 30, From ae8fac80fe83718a1fecf7c151b0ba3a136bd02c Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Wed, 1 May 2024 16:01:55 +0200 Subject: [PATCH 5/8] RegionX Treasury (#106) * Treasury * delegated referenda instance * config wip * compiles * Native referenda tracks * native referenda * tests * clippy fix * track fixes * fix track info * .. --- Cargo.lock | 1 + Cargo.toml | 1 + ...{governance.js => delegated-governance.js} | 6 +- e2e_tests/native-governance.js | 35 +++++ runtime/regionx/Cargo.toml | 4 + runtime/regionx/src/governance/mod.rs | 56 +++++-- runtime/regionx/src/governance/origins.rs | 19 ++- runtime/regionx/src/governance/tracks.rs | 144 +++++++++++++++++- runtime/regionx/src/lib.rs | 98 ++++++++---- ...ce.toml => 0004-delegated-governance.toml} | 0 .../0004-delegated-governance.zndsl | 10 ++ zombienet_tests/0005-native-governance.toml | 23 +++ ...nce.zndsl => 0005-native-governance.zndsl} | 4 +- 13 files changed, 353 insertions(+), 48 deletions(-) rename e2e_tests/{governance.js => delegated-governance.js} (90%) create mode 100644 e2e_tests/native-governance.js rename zombienet_tests/{0004-governance.toml => 0004-delegated-governance.toml} (100%) create mode 100644 zombienet_tests/0004-delegated-governance.zndsl create mode 100644 zombienet_tests/0005-native-governance.toml rename zombienet_tests/{0004-governance.zndsl => 0005-native-governance.zndsl} (57%) diff --git a/Cargo.lock b/Cargo.lock index 40132f5a..29f202f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9469,6 +9469,7 @@ dependencies = [ "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", "pallet-utility", "pallet-whitelist", "pallet-xcm", diff --git a/Cargo.toml b/Cargo.toml index 2e3e76e5..c37a292b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ pallet-multisig = { version = "28.0.0", default-features = false } pallet-proxy = { version = "28.0.0", default-features = false } pallet-preimage = { version = "28.0.0", default-features = false } pallet-scheduler = { version = "29.0.0", default-features = false } +pallet-treasury = { version = "27.0.0", default-features = false } pallet-utility = { version = "28.0.0", default-features = false } pallet-whitelist = { version = "27.0.0", default-features = false } sp-api = { version = "26.0.0", default-features = false } diff --git a/e2e_tests/governance.js b/e2e_tests/delegated-governance.js similarity index 90% rename from e2e_tests/governance.js rename to e2e_tests/delegated-governance.js index 072cc953..86b6a13f 100644 --- a/e2e_tests/governance.js +++ b/e2e_tests/delegated-governance.js @@ -31,17 +31,17 @@ async function run(nodeName, networkInfo, _jsArgs) { const remarkCallBytes = api.tx.system.remark("hey").toU8a(); await submitExtrinsic(alice, api.tx.preimage.notePreimage(remarkCallBytes), {}); - const submitProposal = api.tx.referenda.submit( + const submitProposal = api.tx.delegatedReferenda.submit( { system: "Root" }, { Lookup: { hash: PREIMAGE_HASH, len: remarkCallBytes.length } }, { After: 5 }, ); await submitExtrinsic(anna, submitProposal, { assetId: RELAY_ASSET_ID }); - const placeDeposit = api.tx.referenda.placeDecisionDeposit(0); + const placeDeposit = api.tx.delegatedReferenda.placeDecisionDeposit(0); await submitExtrinsic(anna, placeDeposit, { assetId: RELAY_ASSET_ID }); - const voteCall = api.tx.convictionVoting.vote(0, { + const voteCall = api.tx.delegatedConvictionVoting.vote(0, { // Voting with relay chain tokens. We know this is true; otherwise, this call // would fail, given that Anna doesn't have 10^16 RegionX tokens. Standard: { vote: { aye: true, conviction: "None" }, balance: 10n ** 16n }, diff --git a/e2e_tests/native-governance.js b/e2e_tests/native-governance.js new file mode 100644 index 00000000..d3a91a77 --- /dev/null +++ b/e2e_tests/native-governance.js @@ -0,0 +1,35 @@ +const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); +const { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } = require("./common"); + +const PREIMAGE_HASH = "0x0ccf4369e9a9f88f035828ba0dd5da645d5c0fa7baa86bdc8d7a80c183ab84c9"; + +async function run(nodeName, networkInfo, _jsArgs) { + const { wsUri } = networkInfo.nodesByName[nodeName]; + const api = await ApiPromise.create({provider: new WsProvider(wsUri)}); + + // account to submit tx + const keyring = new Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + + await setupRelayAsset(api, alice); + + const spendCallBytes = api.tx.treasury.spendLocal(10n**6n, alice.address).toU8a(); + await submitExtrinsic(alice, api.tx.preimage.notePreimage(spendCallBytes), {}); + + const submitProposal = api.tx.nativeReferenda.submit( + { Origins: "SmallTipper" }, + { Lookup: { hash: PREIMAGE_HASH, len: spendCallBytes.length } }, + { After: 5 }, + ); + await submitExtrinsic(alice, submitProposal, {}); + + const placeDeposit = api.tx.nativeReferenda.placeDecisionDeposit(0); + await submitExtrinsic(alice, placeDeposit, {}); + + const voteCall = api.tx.nativeConvictionVoting.vote(0, { + Standard: { vote: { aye: true, conviction: "None" }, balance: 10n ** 16n }, + }); + await submitExtrinsic(alice, voteCall, {}); +} + +module.exports = { run }; diff --git a/runtime/regionx/Cargo.toml b/runtime/regionx/Cargo.toml index 33813018..79951439 100644 --- a/runtime/regionx/Cargo.toml +++ b/runtime/regionx/Cargo.toml @@ -62,6 +62,7 @@ pallet-preimage = { workspace = true } pallet-session = { workspace = true } pallet-sudo = { workspace = true } pallet-scheduler = { workspace = true } +pallet-treasury = { workspace = true } pallet-timestamp = { workspace = true } pallet-transaction-payment = { workspace = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true } @@ -153,6 +154,7 @@ std = [ "pallet-session/std", "pallet-sudo/std", "pallet-scheduler/std", + "pallet-treasury/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", @@ -210,6 +212,7 @@ runtime-benchmarks = [ "pallet-regions/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", @@ -254,6 +257,7 @@ try-runtime = [ "pallet-session/try-runtime", "pallet-sudo/try-runtime", "pallet-scheduler/try-runtime", + "pallet-treasury/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", "pallet-utility/try-runtime", diff --git a/runtime/regionx/src/governance/mod.rs b/runtime/regionx/src/governance/mod.rs index 57f9ff26..67c0fccb 100644 --- a/runtime/regionx/src/governance/mod.rs +++ b/runtime/regionx/src/governance/mod.rs @@ -16,7 +16,7 @@ use super::*; mod origins; -pub use origins::{pallet_custom_origins, WhitelistedCaller}; +pub use origins::{pallet_custom_origins, Spender, WhitelistedCaller}; mod tracks; pub use tracks::*; @@ -33,11 +33,17 @@ type EnsureTwoThirdGeneralCouncil = type EnsureTwoThirdTechnicalCommittee = pallet_collective::EnsureProportionAtLeast; +pub type DelegatedReferendaInstance = pallet_referenda::Instance1; +pub type NativeReferendaInstance = pallet_referenda::Instance2; + +pub type DelegatedConvictionVotingInstance = pallet_conviction_voting::Instance1; +pub type NativeConvictionVotingInstance = pallet_conviction_voting::Instance2; + parameter_types! { pub const VoteLockingPeriod: BlockNumber = prod_or_fast!(7 * DAYS, 1); } -impl pallet_conviction_voting::Config for Runtime { +impl pallet_conviction_voting::Config for Runtime { type WeightInfo = (); type RuntimeEvent = RuntimeEvent; type Currency = RelayChainCurrency; @@ -47,16 +53,28 @@ impl pallet_conviction_voting::Config for Runtime { RelayChainCurrency, Self::AccountId, >; - type Polls = Referenda; + type Polls = DelegatedReferenda; +} + +impl pallet_conviction_voting::Config for Runtime { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type VoteLockingPeriod = VoteLockingPeriod; + type MaxVotes = ConstU32<512>; + type MaxTurnout = + frame_support::traits::tokens::currency::ActiveIssuanceOf; + type Polls = NativeReferenda; } parameter_types! { pub const AlarmInterval: BlockNumber = 1; - pub const SubmissionDeposit: Balance = 5 * KSM; pub const UndecidingTimeout: BlockNumber = 14 * DAYS; + pub const DelegatedReferendaSubmissionDeposit: Balance = KSM; + pub const NativeReferendaSubmissionDeposit: Balance = 50 * REGX; } -impl pallet_referenda::Config for Runtime { +impl pallet_referenda::Config for Runtime { type WeightInfo = (); type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; @@ -68,13 +86,33 @@ impl pallet_referenda::Config for Runtime { type KillOrigin = EitherOfDiverse; type Slash = (); // TODO: treasury - type Votes = pallet_conviction_voting::VotesOf; - type Tally = pallet_conviction_voting::TallyOf; - type SubmissionDeposit = SubmissionDeposit; + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = DelegatedReferendaSubmissionDeposit; + type MaxQueued = ConstU32<50>; + type UndecidingTimeout = UndecidingTimeout; + type AlarmInterval = AlarmInterval; + type Tracks = DelegatedReferendaTrackInfo; + type Preimages = Preimage; +} + +impl pallet_referenda::Config for Runtime { + type WeightInfo = (); + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Currency = Balances; + type SubmitOrigin = frame_system::EnsureSigned; + type CancelOrigin = EnsureTwoThirdGeneralCouncil; + type KillOrigin = EnsureTwoThirdGeneralCouncil; + type Slash = Treasury; + type Votes = pallet_conviction_voting::VotesOf; + type Tally = pallet_conviction_voting::TallyOf; + type SubmissionDeposit = NativeReferendaSubmissionDeposit; type MaxQueued = ConstU32<50>; type UndecidingTimeout = UndecidingTimeout; type AlarmInterval = AlarmInterval; - type Tracks = TracksInfo; + type Tracks = NativeReferendaTrackInfo; type Preimages = Preimage; } diff --git a/runtime/regionx/src/governance/origins.rs b/runtime/regionx/src/governance/origins.rs index 7eb0c321..5ee5694c 100644 --- a/runtime/regionx/src/governance/origins.rs +++ b/runtime/regionx/src/governance/origins.rs @@ -1,3 +1,18 @@ +// This file is part of RegionX. +// +// RegionX 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. +// +// RegionX 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 RegionX. If not, see . + pub use pallet_custom_origins::*; // TODO: investigate warning @@ -18,6 +33,8 @@ pub mod pallet_custom_origins { pub enum Origin { /// Origin able to dispatch a whitelisted call. WhitelistedCaller, + /// Origin for spending (any amount of) funds. + Treasurer, /// Origin able to spend up to 500 REGX from the treasury at once. SmallTipper, /// Origin able to spend up to 2,000 REGX from the treasury at once. @@ -60,7 +77,7 @@ pub mod pallet_custom_origins { }; () => {} } - decl_unit_ensures!(WhitelistedCaller); + decl_unit_ensures!(WhitelistedCaller, Treasurer); macro_rules! decl_ensure { ( diff --git a/runtime/regionx/src/governance/tracks.rs b/runtime/regionx/src/governance/tracks.rs index 74196a63..0cb4a0a7 100644 --- a/runtime/regionx/src/governance/tracks.rs +++ b/runtime/regionx/src/governance/tracks.rs @@ -20,16 +20,31 @@ const fn percent(x: i32) -> sp_runtime::FixedI64 { sp_runtime::FixedI64::from_rational(x as u128, 100) } -// Same curve as on Polkadot. +// Same curves as on Polkadot: + const APP_ROOT: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); const SUP_ROOT: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); -// Same curve as on Polkadot. const APP_WHITELISTED_CALLER: Curve = Curve::make_reciprocal(16, 28 * 24, percent(96), percent(50), percent(100)); const SUP_WHITELISTED_CALLER: Curve = Curve::make_reciprocal(1, 28, percent(20), percent(5), percent(50)); +const APP_TREASURER: Curve = Curve::make_reciprocal(4, 28, percent(80), percent(50), percent(100)); +const SUP_TREASURER: Curve = Curve::make_linear(28, 28, percent(0), percent(50)); + +const APP_SMALL_TIPPER: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); +const SUP_SMALL_TIPPER: Curve = Curve::make_reciprocal(1, 28, percent(4), percent(0), percent(50)); +const APP_BIG_TIPPER: Curve = Curve::make_linear(10, 28, percent(50), percent(100)); +const SUP_BIG_TIPPER: Curve = Curve::make_reciprocal(8, 28, percent(1), percent(0), percent(50)); +const APP_SMALL_SPENDER: Curve = Curve::make_linear(17, 28, percent(50), percent(100)); +const SUP_SMALL_SPENDER: Curve = + Curve::make_reciprocal(12, 28, percent(1), percent(0), percent(50)); +const APP_MEDIUM_SPENDER: Curve = Curve::make_linear(23, 28, percent(50), percent(100)); +const SUP_MEDIUM_SPENDER: Curve = + Curve::make_reciprocal(16, 28, percent(1), percent(0), percent(50)); +const APP_BIG_SPENDER: Curve = Curve::make_linear(28, 28, percent(50), percent(100)); +const SUP_BIG_SPENDER: Curve = Curve::make_reciprocal(20, 28, percent(1), percent(0), percent(50)); -const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 2] = [ +const DELEGATED_REFERENDA_TRACKS: [(u16, pallet_referenda::TrackInfo); 2] = [ ( 0, pallet_referenda::TrackInfo { @@ -60,12 +75,99 @@ const TRACKS_DATA: [(u16, pallet_referenda::TrackInfo); 2] ), ]; -pub struct TracksInfo; -impl pallet_referenda::TracksInfo for TracksInfo { +const NATIVE_REFERENDA_TRACKS: [(u16, pallet_referenda::TrackInfo); 6] = [ + ( + 0, + pallet_referenda::TrackInfo { + name: "treasurer", + max_deciding: 5, + decision_deposit: 20_000 * REGX, + prepare_period: 12 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 48 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_TREASURER, + min_support: SUP_TREASURER, + }, + ), + ( + 1, + pallet_referenda::TrackInfo { + name: "small_tipper", + max_deciding: 50, + decision_deposit: 100 * REGX, + prepare_period: 30 * MINUTES, + decision_period: 7 * DAYS, + confirm_period: 4 * HOURS, + min_enactment_period: 30 * MINUTES, + min_approval: APP_SMALL_TIPPER, + min_support: SUP_SMALL_TIPPER, + }, + ), + ( + 2, + pallet_referenda::TrackInfo { + name: "big_tipper", + max_deciding: 20, + decision_deposit: 250 * REGX, + prepare_period: 2 * HOURS, + decision_period: 10 * DAYS, + confirm_period: 8 * HOURS, + min_enactment_period: 4 * HOURS, + min_approval: APP_BIG_TIPPER, + min_support: SUP_BIG_TIPPER, + }, + ), + ( + 3, + pallet_referenda::TrackInfo { + name: "small_spender", + max_deciding: 10, + decision_deposit: 1000 * REGX, + prepare_period: 4 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 12 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_SMALL_SPENDER, + min_support: SUP_SMALL_SPENDER, + }, + ), + ( + 4, + pallet_referenda::TrackInfo { + name: "medium_spender", + max_deciding: 5, + decision_deposit: 2000 * REGX, + prepare_period: 8 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 24 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_MEDIUM_SPENDER, + min_support: SUP_MEDIUM_SPENDER, + }, + ), + ( + 5, + pallet_referenda::TrackInfo { + name: "big_spender", + max_deciding: 5, + decision_deposit: 5000 * REGX, + prepare_period: 12 * HOURS, + decision_period: 14 * DAYS, + confirm_period: 48 * HOURS, + min_enactment_period: 24 * HOURS, + min_approval: APP_BIG_SPENDER, + min_support: SUP_BIG_SPENDER, + }, + ), +]; + +pub struct DelegatedReferendaTrackInfo; +impl pallet_referenda::TracksInfo for DelegatedReferendaTrackInfo { type Id = u16; type RuntimeOrigin = ::PalletsOrigin; fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { - &TRACKS_DATA[..] + &DELEGATED_REFERENDA_TRACKS[..] } fn track_for(id: &Self::RuntimeOrigin) -> Result { if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { @@ -79,9 +181,37 @@ impl pallet_referenda::TracksInfo for TracksInfo { _ => Err(()), } } else { + // Treasury is only controlable with native tokens. + Err(()) + } + } +} +pallet_referenda::impl_tracksinfo_get!(DelegatedReferendaTrackInfo, Balance, BlockNumber); + +pub struct NativeReferendaTrackInfo; +impl pallet_referenda::TracksInfo for NativeReferendaTrackInfo { + type Id = u16; + type RuntimeOrigin = ::PalletsOrigin; + fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { + &NATIVE_REFERENDA_TRACKS[..] + } + fn track_for(id: &Self::RuntimeOrigin) -> Result { + if let Ok(_system_origin) = frame_system::RawOrigin::try_from(id.clone()) { // Root is the only avaialable origin for relay chain asset holders. Err(()) + } else if let Ok(custom_origin) = origins::Origin::try_from(id.clone()) { + match custom_origin { + origins::Origin::Treasurer => Ok(0), + origins::Origin::SmallTipper => Ok(1), + origins::Origin::BigTipper => Ok(2), + origins::Origin::SmallSpender => Ok(3), + origins::Origin::MediumSpender => Ok(4), + origins::Origin::BigSpender => Ok(5), + _ => Err(()), + } + } else { + Err(()) } } } -pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); +pallet_referenda::impl_tracksinfo_get!(NativeReferendaTrackInfo, Balance, BlockNumber); diff --git a/runtime/regionx/src/lib.rs b/runtime/regionx/src/lib.rs index 951a5d40..ea252ec7 100644 --- a/runtime/regionx/src/lib.rs +++ b/runtime/regionx/src/lib.rs @@ -27,7 +27,7 @@ mod weights; pub mod xcm_config; mod governance; -use governance::pallet_custom_origins; +use governance::{pallet_custom_origins, Spender}; mod impls; mod ismp; @@ -37,7 +37,9 @@ use impls::*; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::traits::{ - fungible::HoldConsideration, EqualPrivilegeOnly, LinearStoragePrice, TransformOrigin, + fungible::HoldConsideration, + tokens::{PayFromAccount, UnityAssetBalanceConversion}, + EqualPrivilegeOnly, LinearStoragePrice, TransformOrigin, }; use pallet_regions::primitives::StateMachineHeightProvider as StateMachineHeightProviderT; use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; @@ -47,7 +49,7 @@ use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT}, + traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, IdentityLookup}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; @@ -705,6 +707,45 @@ impl pallet_scheduler::Config for Runtime { type Preimages = Preimage; } +parameter_types! { + pub const TreasuryPalletId: PalletId = PalletId(*b"rgx/trsy"); + pub RegionXTreasuryAccount: AccountId = TreasuryPalletId::get().into_account_truncating(); + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 100 * REGX; + pub const ProposalBondMaximum: Balance = 5_000 * REGX; + pub const SpendPeriod: BlockNumber = 7 * DAYS; + pub const PayoutPeriod: BlockNumber = 30 * DAYS; + pub const MaxApprovals: u32 = 50; + pub const Burn: Permill = Permill::from_percent(0); +} + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryPalletId; + type Currency = Balances; + type ApproveOrigin = Spender; + type RejectOrigin = Spender; + type RuntimeEvent = RuntimeEvent; + type OnSlash = Treasury; + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type ProposalBondMaximum = ProposalBondMaximum; + type SpendPeriod = SpendPeriod; + type Burn = Burn; + type BurnDestination = (); + type MaxApprovals = MaxApprovals; + type WeightInfo = (); + type SpendFunds = (); + type SpendOrigin = Spender; + type AssetKind = (); + type Beneficiary = AccountId; + type BeneficiaryLookup = IdentityLookup; + type Paymaster = PayFromAccount; + type BalanceConverter = UnityAssetBalanceConversion; + type PayoutPeriod = PayoutPeriod; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -729,39 +770,44 @@ construct_runtime!( // Governance Sudo: pallet_sudo = 20, // TODO: leave this only for testnets - Referenda: pallet_referenda = 21, - ConvictionVoting: pallet_conviction_voting = 22, - GeneralCouncil: pallet_collective:: = 23, - TechnicalCommittee: pallet_collective:: = 24, - GeneralCouncilMembership: pallet_membership:: = 25, - TechnicalCommitteeMembership: pallet_membership:: = 26, - Origins: pallet_custom_origins = 27, - Whitelist: pallet_whitelist = 28, + DelegatedReferenda: pallet_referenda:: = 21, + NativeReferenda: pallet_referenda:: = 22, + DelegatedConvictionVoting: pallet_conviction_voting:: = 23, + NativeConvictionVoting: pallet_conviction_voting:: = 24, + GeneralCouncil: pallet_collective:: = 25, + TechnicalCommittee: pallet_collective:: = 26, + GeneralCouncilMembership: pallet_membership:: = 27, + TechnicalCommitteeMembership: pallet_membership:: = 28, + Origins: pallet_custom_origins = 29, + Whitelist: pallet_whitelist = 30, // Collator support. The order of these 4 are important and shall not change. - Authorship: pallet_authorship = 30, - CollatorSelection: pallet_collator_selection = 31, - Session: pallet_session = 32, - Aura: pallet_aura = 33, - AuraExt: cumulus_pallet_aura_ext = 34, + Authorship: pallet_authorship = 40, + CollatorSelection: pallet_collator_selection = 41, + Session: pallet_session = 42, + Aura: pallet_aura = 43, + AuraExt: cumulus_pallet_aura_ext = 44, + + // Treasury + Treasury: pallet_treasury = 50, // Handy utilities - Utility: pallet_utility = 40, - Multisig: pallet_multisig = 41, - Proxy: pallet_proxy = 42, + Utility: pallet_utility = 60, + Multisig: pallet_multisig = 61, + Proxy: pallet_proxy = 62, // XCM helpers. - XcmpQueue: cumulus_pallet_xcmp_queue = 50, - PolkadotXcm: pallet_xcm = 51, - CumulusXcm: cumulus_pallet_xcm = 52, - MessageQueue: pallet_message_queue = 53, + XcmpQueue: cumulus_pallet_xcmp_queue = 70, + PolkadotXcm: pallet_xcm = 71, + CumulusXcm: cumulus_pallet_xcm = 72, + MessageQueue: pallet_message_queue = 73, // ISMP - Ismp: pallet_ismp = 60, - IsmpParachain: ismp_parachain = 61, + Ismp: pallet_ismp = 80, + IsmpParachain: ismp_parachain = 81, // Main stage: - Regions: pallet_regions = 70, + Regions: pallet_regions = 90, } ); diff --git a/zombienet_tests/0004-governance.toml b/zombienet_tests/0004-delegated-governance.toml similarity index 100% rename from zombienet_tests/0004-governance.toml rename to zombienet_tests/0004-delegated-governance.toml diff --git a/zombienet_tests/0004-delegated-governance.zndsl b/zombienet_tests/0004-delegated-governance.zndsl new file mode 100644 index 00000000..c986ab7a --- /dev/null +++ b/zombienet_tests/0004-delegated-governance.zndsl @@ -0,0 +1,10 @@ +Description: Native currency fee payment +Network: ./0004-delegated-governance.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/delegated-governance.js return is 0 within 400 seconds diff --git a/zombienet_tests/0005-native-governance.toml b/zombienet_tests/0005-native-governance.toml new file mode 100644 index 00000000..635f5419 --- /dev/null +++ b/zombienet_tests/0005-native-governance.toml @@ -0,0 +1,23 @@ +[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 = 2000 +addToGenesis = false + + [parachains.collator] + name = "regionx-collator01" + command = "regionx-node" + args = [ "-lruntime=debug,parachain=trace" ] diff --git a/zombienet_tests/0004-governance.zndsl b/zombienet_tests/0005-native-governance.zndsl similarity index 57% rename from zombienet_tests/0004-governance.zndsl rename to zombienet_tests/0005-native-governance.zndsl index 8e6a6175..3002d9aa 100644 --- a/zombienet_tests/0004-governance.zndsl +++ b/zombienet_tests/0005-native-governance.zndsl @@ -1,5 +1,5 @@ Description: Native currency fee payment -Network: ./0004-governance.toml +Network: ./0005-native-governance.toml Creds: config rococo-validator01: is up @@ -7,4 +7,4 @@ rococo-validator02: is up rococo-validator01: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/governance.js return is 0 within 400 seconds +regionx-collator01: js-script ../e2e_tests/native-governance.js return is 0 within 400 seconds From fb260f15a51ec5f62d76e4f9177960a47db13898 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Mon, 6 May 2024 19:40:26 +0200 Subject: [PATCH 6/8] Reorganize e2e tests (#109) * Reorganize e2e tests * remove accidentally added directory * unused import * some fixes --------- Co-authored-by: cuteolaf --- e2e_tests/common.js | 2 +- e2e_tests/{custom-fee-payment.js => fee-payment/custom.js} | 6 ++---- e2e_tests/{native-fee-payment.js => fee-payment/native.js} | 2 +- .../{delegated-governance.js => governance/delegated.js} | 2 +- e2e_tests/{native-governance.js => governance/native.js} | 2 +- e2e_tests/package.json | 2 +- zombienet_tests/0002-native-fee-payment.zndsl | 2 +- zombienet_tests/0003-custom-fee-payment.zndsl | 2 +- zombienet_tests/0004-delegated-governance.zndsl | 2 +- zombienet_tests/0005-native-governance.zndsl | 2 +- 10 files changed, 11 insertions(+), 13 deletions(-) rename e2e_tests/{custom-fee-payment.js => fee-payment/custom.js} (94%) rename e2e_tests/{native-fee-payment.js => fee-payment/native.js} (92%) rename e2e_tests/{delegated-governance.js => governance/delegated.js} (99%) rename e2e_tests/{native-governance.js => governance/native.js} (93%) diff --git a/e2e_tests/common.js b/e2e_tests/common.js index 60b7a576..0e5df279 100644 --- a/e2e_tests/common.js +++ b/e2e_tests/common.js @@ -17,7 +17,7 @@ async function submitExtrinsic(signer, call, options) { } else if (result.isError) { console.log(`Transaction error`); unsub(); - return resolve(); + return reject(); } }); }); diff --git a/e2e_tests/custom-fee-payment.js b/e2e_tests/fee-payment/custom.js similarity index 94% rename from e2e_tests/custom-fee-payment.js rename to e2e_tests/fee-payment/custom.js index ab0db92c..6f4d90f9 100644 --- a/e2e_tests/custom-fee-payment.js +++ b/e2e_tests/fee-payment/custom.js @@ -1,13 +1,11 @@ const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); -const { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } = require("./common"); +const { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } = require("../common"); 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/native-fee-payment.js b/e2e_tests/fee-payment/native.js similarity index 92% rename from e2e_tests/native-fee-payment.js rename to e2e_tests/fee-payment/native.js index affa8e9c..6598e5c9 100644 --- a/e2e_tests/native-fee-payment.js +++ b/e2e_tests/fee-payment/native.js @@ -1,5 +1,5 @@ const { ApiPromise, WsProvider } = require("@polkadot/api"); -const { submitExtrinsic } = require("./common"); +const { submitExtrinsic } = require("../common"); async function run(nodeName, networkInfo, _jsArgs) { const { wsUri } = networkInfo.nodesByName[nodeName]; diff --git a/e2e_tests/delegated-governance.js b/e2e_tests/governance/delegated.js similarity index 99% rename from e2e_tests/delegated-governance.js rename to e2e_tests/governance/delegated.js index 86b6a13f..aa073d57 100644 --- a/e2e_tests/delegated-governance.js +++ b/e2e_tests/governance/delegated.js @@ -1,5 +1,5 @@ const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); -const { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } = require("./common"); +const { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } = require("../common"); const PREIMAGE_HASH = "0xb8375f7ca0c64a384f2dd643a0d520977f3aae06e64afb8c960891eee5147bd1"; diff --git a/e2e_tests/native-governance.js b/e2e_tests/governance/native.js similarity index 93% rename from e2e_tests/native-governance.js rename to e2e_tests/governance/native.js index d3a91a77..d2b33318 100644 --- a/e2e_tests/native-governance.js +++ b/e2e_tests/governance/native.js @@ -1,5 +1,5 @@ const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); -const { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } = require("./common"); +const { submitExtrinsic, setupRelayAsset } = require("../common"); const PREIMAGE_HASH = "0x0ccf4369e9a9f88f035828ba0dd5da645d5c0fa7baa86bdc8d7a80c183ab84c9"; diff --git a/e2e_tests/package.json b/e2e_tests/package.json index 488bb14c..48b819dc 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", diff --git a/zombienet_tests/0002-native-fee-payment.zndsl b/zombienet_tests/0002-native-fee-payment.zndsl index 22446fd9..e87c365e 100644 --- a/zombienet_tests/0002-native-fee-payment.zndsl +++ b/zombienet_tests/0002-native-fee-payment.zndsl @@ -7,4 +7,4 @@ bob: is up alice: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/native-fee-payment.js return is 0 within 200 seconds +regionx-collator01: js-script ../e2e_tests/fee-payment/native.js return is 0 within 200 seconds diff --git a/zombienet_tests/0003-custom-fee-payment.zndsl b/zombienet_tests/0003-custom-fee-payment.zndsl index 4625233d..3ed50752 100644 --- a/zombienet_tests/0003-custom-fee-payment.zndsl +++ b/zombienet_tests/0003-custom-fee-payment.zndsl @@ -7,4 +7,4 @@ rococo-validator02: is up rococo-validator01: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/custom-fee-payment.js return is 0 within 400 seconds +regionx-collator01: js-script ../e2e_tests/fee-payment/custom.js return is 0 within 400 seconds diff --git a/zombienet_tests/0004-delegated-governance.zndsl b/zombienet_tests/0004-delegated-governance.zndsl index c986ab7a..f81632ce 100644 --- a/zombienet_tests/0004-delegated-governance.zndsl +++ b/zombienet_tests/0004-delegated-governance.zndsl @@ -7,4 +7,4 @@ rococo-validator02: is up rococo-validator01: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/delegated-governance.js return is 0 within 400 seconds +regionx-collator01: js-script ../e2e_tests/governance/delegated.js return is 0 within 400 seconds diff --git a/zombienet_tests/0005-native-governance.zndsl b/zombienet_tests/0005-native-governance.zndsl index 3002d9aa..896b4767 100644 --- a/zombienet_tests/0005-native-governance.zndsl +++ b/zombienet_tests/0005-native-governance.zndsl @@ -7,4 +7,4 @@ rococo-validator02: is up rococo-validator01: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/native-governance.js return is 0 within 400 seconds +regionx-collator01: js-script ../e2e_tests/governance/native.js return is 0 within 400 seconds From ec5d836c2a0a67cdd86bea9ee5e0827026d3473b Mon Sep 17 00:00:00 2001 From: cuteolaf Date: Mon, 6 May 2024 12:36:01 -0700 Subject: [PATCH 7/8] update origins & tracks (#111) --- runtime/regionx/src/governance/origins.rs | 3 +-- runtime/regionx/src/governance/tracks.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/runtime/regionx/src/governance/origins.rs b/runtime/regionx/src/governance/origins.rs index 5ee5694c..d366bcec 100644 --- a/runtime/regionx/src/governance/origins.rs +++ b/runtime/regionx/src/governance/origins.rs @@ -15,7 +15,6 @@ pub use pallet_custom_origins::*; -// TODO: investigate warning #[allow(unused_imports)] #[frame_support::pallet] pub mod pallet_custom_origins { @@ -117,7 +116,7 @@ pub mod pallet_custom_origins { SmallTipper = 500 * REGX, BigTipper = 2000 * REGX, SmallSpender = 50_000 * REGX, - MediumSpender = 100_000 * REGX, + MediumSpender = 200_000 * REGX, BigSpender = 500_000 * REGX, } } diff --git a/runtime/regionx/src/governance/tracks.rs b/runtime/regionx/src/governance/tracks.rs index 0cb4a0a7..497bbdd3 100644 --- a/runtime/regionx/src/governance/tracks.rs +++ b/runtime/regionx/src/governance/tracks.rs @@ -181,7 +181,7 @@ impl pallet_referenda::TracksInfo for DelegatedReferendaTr _ => Err(()), } } else { - // Treasury is only controlable with native tokens. + // Treasury is only controllable with native tokens. Err(()) } } @@ -197,7 +197,7 @@ impl pallet_referenda::TracksInfo for NativeReferendaTrack } fn track_for(id: &Self::RuntimeOrigin) -> Result { if let Ok(_system_origin) = frame_system::RawOrigin::try_from(id.clone()) { - // Root is the only avaialable origin for relay chain asset holders. + // Root is the only available origin for relay chain asset holders. Err(()) } else if let Ok(custom_origin) = origins::Origin::try_from(id.clone()) { match custom_origin { From 42d4e469034516586d42420368097404aa089612 Mon Sep 17 00:00:00 2001 From: cuteolaf Date: Mon, 6 May 2024 12:44:44 -0700 Subject: [PATCH 8/8] use typescript for e2e tests (#110) --- .gitignore | 1 + e2e_tests/{common.js => common.ts} | 12 ++- e2e_tests/fee-payment/custom.js | 73 ------------------- e2e_tests/fee-payment/custom.ts | 73 +++++++++++++++++++ e2e_tests/fee-payment/native.js | 18 ----- e2e_tests/fee-payment/native.ts | 18 +++++ e2e_tests/governance/delegated.js | 52 ------------- e2e_tests/governance/delegated.ts | 52 +++++++++++++ e2e_tests/governance/native.js | 35 --------- e2e_tests/governance/native.ts | 35 +++++++++ e2e_tests/package.json | 6 +- e2e_tests/tsconfig.json | 15 ++++ zombienet_tests/0002-native-fee-payment.zndsl | 2 +- zombienet_tests/0003-custom-fee-payment.zndsl | 2 +- .../0004-delegated-governance.zndsl | 2 +- zombienet_tests/0005-native-governance.zndsl | 2 +- 16 files changed, 210 insertions(+), 188 deletions(-) rename e2e_tests/{common.js => common.ts} (72%) delete mode 100644 e2e_tests/fee-payment/custom.js create mode 100644 e2e_tests/fee-payment/custom.ts delete mode 100644 e2e_tests/fee-payment/native.js create mode 100644 e2e_tests/fee-payment/native.ts delete mode 100644 e2e_tests/governance/delegated.js create mode 100644 e2e_tests/governance/delegated.ts delete mode 100644 e2e_tests/governance/native.js create mode 100644 e2e_tests/governance/native.ts create mode 100644 e2e_tests/tsconfig.json diff --git a/.gitignore b/.gitignore index ca01b4c0..6bacf47e 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ bin/ node_modules **/package-lock.json +**/build \ No newline at end of file diff --git a/e2e_tests/common.js b/e2e_tests/common.ts similarity index 72% rename from e2e_tests/common.js rename to e2e_tests/common.ts index 0e5df279..04391000 100644 --- a/e2e_tests/common.js +++ b/e2e_tests/common.ts @@ -1,6 +1,10 @@ -const RELAY_ASSET_ID = 1; +import { ApiPromise } from "@polkadot/api"; +import { SubmittableExtrinsic, SignerOptions } from "@polkadot/api/types"; +import { KeyringPair } from "@polkadot/keyring/types"; -async function submitExtrinsic(signer, call, options) { +const RELAY_ASSET_ID = 1; + +async function submitExtrinsic(signer: KeyringPair, call: SubmittableExtrinsic<"promise">, options: Partial): 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,4 +54,4 @@ async function setupRelayAsset(api, signer) { await submitExtrinsic(signer, sudoCall, {}); } -module.exports = { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } +export { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } diff --git a/e2e_tests/fee-payment/custom.js b/e2e_tests/fee-payment/custom.js deleted file mode 100644 index 6f4d90f9..00000000 --- a/e2e_tests/fee-payment/custom.js +++ /dev/null @@ -1,73 +0,0 @@ -const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); -const { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } = require("../common"); - -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 regionXApi = await ApiPromise.create({ - provider: new WsProvider(regionXUri), - signedExtensions: { - ChargeAssetTxPayment: { - extrinsic: { - tip: "Compact", - assetId: "Option", - }, - payload: {}, - }, - }, - }); - - // account to submit tx - const keyring = new zombie.Keyring({ type: "sr25519" }); - const alice = keyring.addFromUri("//Alice"); - - const setXcmVersion = rococoApi.tx.xcmPallet.forceDefaultXcmVersion([3]); - await submitExtrinsic(alice, rococoApi.tx.sudo.sudo(setXcmVersion), {}); - - 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, {}); - - // Try to pay for fees with relay chain asset. - const remarkCall = regionXApi.tx.system.remark("0x44"); - await submitExtrinsic(alice, remarkCall, { assetId: RELAY_ASSET_ID }); -} - -module.exports = { run }; diff --git a/e2e_tests/fee-payment/custom.ts b/e2e_tests/fee-payment/custom.ts new file mode 100644 index 00000000..78c59e13 --- /dev/null +++ b/e2e_tests/fee-payment/custom.ts @@ -0,0 +1,73 @@ +import { ApiPromise, WsProvider, Keyring } from "@polkadot/api"; +import { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } from "../common"; + +async function run(nodeName: string, networkInfo: any, _jsArgs: any) { + const { wsUri: regionXUri } = networkInfo.nodesByName[nodeName]; + const { wsUri: rococoUri } = networkInfo.nodesByName["rococo-validator01"]; + + const rococoApi = await ApiPromise.create({ provider: new WsProvider(rococoUri) }); + const regionXApi = await ApiPromise.create({ + provider: new WsProvider(regionXUri), + signedExtensions: { + ChargeAssetTxPayment: { + extrinsic: { + tip: "Compact", + assetId: "Option", + }, + payload: {}, + }, + }, + }); + + // account to submit tx + const keyring = new Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + + const setXcmVersion = rococoApi.tx.xcmPallet.forceDefaultXcmVersion([3]); + await submitExtrinsic(alice, rococoApi.tx.sudo.sudo(setXcmVersion), {}); + + 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, {}); + + // Try to pay for fees with relay chain asset. + const remarkCall = regionXApi.tx.system.remark("0x44"); + await submitExtrinsic(alice, remarkCall, { assetId: RELAY_ASSET_ID }); +} + +export { run }; diff --git a/e2e_tests/fee-payment/native.js b/e2e_tests/fee-payment/native.js deleted file mode 100644 index 6598e5c9..00000000 --- a/e2e_tests/fee-payment/native.js +++ /dev/null @@ -1,18 +0,0 @@ -const { ApiPromise, WsProvider } = require("@polkadot/api"); -const { submitExtrinsic } = require("../common"); - -async function run(nodeName, networkInfo, _jsArgs) { - const { wsUri } = networkInfo.nodesByName[nodeName]; - const api = await ApiPromise.create({provider: new WsProvider(wsUri)}); - - // account to submit tx - const keyring = new zombie.Keyring({ type: "sr25519" }); - const alice = keyring.addFromUri("//Alice"); - const bob = keyring.addFromUri("//Bob"); - - const call = api.tx.balances.transferKeepAlive(bob.address, 10n**6n); - const sudo = api.tx.sudo.sudo(call); - await submitExtrinsic(alice, sudo, {}); -} - -module.exports = { run }; diff --git a/e2e_tests/fee-payment/native.ts b/e2e_tests/fee-payment/native.ts new file mode 100644 index 00000000..b4fef856 --- /dev/null +++ b/e2e_tests/fee-payment/native.ts @@ -0,0 +1,18 @@ +import { ApiPromise, Keyring, WsProvider } from "@polkadot/api"; +import { submitExtrinsic } from "../common"; + +async function run(nodeName: string, networkInfo: any, _jsArgs: any) { + const { wsUri } = networkInfo.nodesByName[nodeName]; + const api = await ApiPromise.create({ provider: new WsProvider(wsUri) }); + + // account to submit tx + const keyring = new Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + const bob = keyring.addFromUri("//Bob"); + + const call = api.tx.balances.transferKeepAlive(bob.address, 10n ** 6n); + const sudo = api.tx.sudo.sudo(call); + await submitExtrinsic(alice, sudo, {}); +} + +export { run }; diff --git a/e2e_tests/governance/delegated.js b/e2e_tests/governance/delegated.js deleted file mode 100644 index aa073d57..00000000 --- a/e2e_tests/governance/delegated.js +++ /dev/null @@ -1,52 +0,0 @@ -const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); -const { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } = require("../common"); - -const PREIMAGE_HASH = "0xb8375f7ca0c64a384f2dd643a0d520977f3aae06e64afb8c960891eee5147bd1"; - -async function run(nodeName, networkInfo, _jsArgs) { - const { wsUri } = networkInfo.nodesByName[nodeName]; - const api = await ApiPromise.create({ - provider: new WsProvider(wsUri), - signedExtensions: { - ChargeAssetTxPayment: { - extrinsic: { - tip: "Compact", - assetId: "Option", - }, - payload: {}, - }, - }, - }); - - // account to submit tx - const keyring = new Keyring({ type: "sr25519" }); - const alice = keyring.addFromUri("//Alice"); - const anna = keyring.addFromUri("//Anna"); - - await setupRelayAsset(api, alice); - - const giveBalanceCall = api.tx.tokens.setBalance(anna.address, RELAY_ASSET_ID, 10n ** 18n, 0); - await submitExtrinsic(alice, api.tx.sudo.sudo(giveBalanceCall), {}); - - const remarkCallBytes = api.tx.system.remark("hey").toU8a(); - await submitExtrinsic(alice, api.tx.preimage.notePreimage(remarkCallBytes), {}); - - const submitProposal = api.tx.delegatedReferenda.submit( - { system: "Root" }, - { Lookup: { hash: PREIMAGE_HASH, len: remarkCallBytes.length } }, - { After: 5 }, - ); - await submitExtrinsic(anna, submitProposal, { assetId: RELAY_ASSET_ID }); - - const placeDeposit = api.tx.delegatedReferenda.placeDecisionDeposit(0); - await submitExtrinsic(anna, placeDeposit, { assetId: RELAY_ASSET_ID }); - - const voteCall = api.tx.delegatedConvictionVoting.vote(0, { - // Voting with relay chain tokens. We know this is true; otherwise, this call - // would fail, given that Anna doesn't have 10^16 RegionX tokens. - Standard: { vote: { aye: true, conviction: "None" }, balance: 10n ** 16n }, - }); - await submitExtrinsic(anna, voteCall, { assetId: RELAY_ASSET_ID }); -} - -module.exports = { run }; diff --git a/e2e_tests/governance/delegated.ts b/e2e_tests/governance/delegated.ts new file mode 100644 index 00000000..960428f6 --- /dev/null +++ b/e2e_tests/governance/delegated.ts @@ -0,0 +1,52 @@ +import { ApiPromise, WsProvider, Keyring } from "@polkadot/api"; +import { submitExtrinsic, setupRelayAsset, RELAY_ASSET_ID } from "../common"; + +const PREIMAGE_HASH = "0xb8375f7ca0c64a384f2dd643a0d520977f3aae06e64afb8c960891eee5147bd1"; + +async function run(nodeName: string, networkInfo: any, _jsArgs: any) { + const { wsUri } = networkInfo.nodesByName[nodeName]; + const api = await ApiPromise.create({ + provider: new WsProvider(wsUri), + signedExtensions: { + ChargeAssetTxPayment: { + extrinsic: { + tip: "Compact", + assetId: "Option", + }, + payload: {}, + }, + }, + }); + + // account to submit tx + const keyring = new Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + const anna = keyring.addFromUri("//Anna"); + + await setupRelayAsset(api, alice); + + const giveBalanceCall = api.tx.tokens.setBalance(anna.address, RELAY_ASSET_ID, 10n ** 18n, 0); + await submitExtrinsic(alice, api.tx.sudo.sudo(giveBalanceCall), {}); + + const remarkCallBytes = api.tx.system.remark("hey").toU8a(); + await submitExtrinsic(alice, api.tx.preimage.notePreimage(remarkCallBytes), {}); + + const submitProposal = api.tx.delegatedReferenda.submit( + { system: "Root" }, + { Lookup: { hash: PREIMAGE_HASH, len: remarkCallBytes.length } }, + { After: 5 } + ); + await submitExtrinsic(anna, submitProposal, { assetId: RELAY_ASSET_ID }); + + const placeDeposit = api.tx.delegatedReferenda.placeDecisionDeposit(0); + await submitExtrinsic(anna, placeDeposit, { assetId: RELAY_ASSET_ID }); + + const voteCall = api.tx.delegatedConvictionVoting.vote(0, { + // Voting with relay chain tokens. We know this is true; otherwise, this call + // would fail, given that Anna doesn't have 10^16 RegionX tokens. + Standard: { vote: { aye: true, conviction: "None" }, balance: 10n ** 16n }, + }); + await submitExtrinsic(anna, voteCall, { assetId: RELAY_ASSET_ID }); +} + +export { run }; diff --git a/e2e_tests/governance/native.js b/e2e_tests/governance/native.js deleted file mode 100644 index d2b33318..00000000 --- a/e2e_tests/governance/native.js +++ /dev/null @@ -1,35 +0,0 @@ -const { ApiPromise, WsProvider, Keyring } = require("@polkadot/api"); -const { submitExtrinsic, setupRelayAsset } = require("../common"); - -const PREIMAGE_HASH = "0x0ccf4369e9a9f88f035828ba0dd5da645d5c0fa7baa86bdc8d7a80c183ab84c9"; - -async function run(nodeName, networkInfo, _jsArgs) { - const { wsUri } = networkInfo.nodesByName[nodeName]; - const api = await ApiPromise.create({provider: new WsProvider(wsUri)}); - - // account to submit tx - const keyring = new Keyring({ type: "sr25519" }); - const alice = keyring.addFromUri("//Alice"); - - await setupRelayAsset(api, alice); - - const spendCallBytes = api.tx.treasury.spendLocal(10n**6n, alice.address).toU8a(); - await submitExtrinsic(alice, api.tx.preimage.notePreimage(spendCallBytes), {}); - - const submitProposal = api.tx.nativeReferenda.submit( - { Origins: "SmallTipper" }, - { Lookup: { hash: PREIMAGE_HASH, len: spendCallBytes.length } }, - { After: 5 }, - ); - await submitExtrinsic(alice, submitProposal, {}); - - const placeDeposit = api.tx.nativeReferenda.placeDecisionDeposit(0); - await submitExtrinsic(alice, placeDeposit, {}); - - const voteCall = api.tx.nativeConvictionVoting.vote(0, { - Standard: { vote: { aye: true, conviction: "None" }, balance: 10n ** 16n }, - }); - await submitExtrinsic(alice, voteCall, {}); -} - -module.exports = { run }; diff --git a/e2e_tests/governance/native.ts b/e2e_tests/governance/native.ts new file mode 100644 index 00000000..40c78e7d --- /dev/null +++ b/e2e_tests/governance/native.ts @@ -0,0 +1,35 @@ +import { ApiPromise, WsProvider, Keyring } from "@polkadot/api"; +import { submitExtrinsic, setupRelayAsset } from "../common"; + +const PREIMAGE_HASH = "0x0ccf4369e9a9f88f035828ba0dd5da645d5c0fa7baa86bdc8d7a80c183ab84c9"; + +async function run(nodeName: string, networkInfo: any, _jsArgs: any) { + const { wsUri } = networkInfo.nodesByName[nodeName]; + const api = await ApiPromise.create({ provider: new WsProvider(wsUri) }); + + // account to submit tx + const keyring = new Keyring({ type: "sr25519" }); + const alice = keyring.addFromUri("//Alice"); + + await setupRelayAsset(api, alice); + + const spendCallBytes = api.tx.treasury.spendLocal(10n ** 6n, alice.address).toU8a(); + await submitExtrinsic(alice, api.tx.preimage.notePreimage(spendCallBytes), {}); + + const submitProposal = api.tx.nativeReferenda.submit( + { Origins: "SmallTipper" }, + { Lookup: { hash: PREIMAGE_HASH, len: spendCallBytes.length } }, + { After: 5 } + ); + await submitExtrinsic(alice, submitProposal, {}); + + const placeDeposit = api.tx.nativeReferenda.placeDecisionDeposit(0); + await submitExtrinsic(alice, placeDeposit, {}); + + const voteCall = api.tx.nativeConvictionVoting.vote(0, { + Standard: { vote: { aye: true, conviction: "None" }, balance: 10n ** 16n }, + }); + await submitExtrinsic(alice, voteCall, {}); +} + +export { run }; diff --git a/e2e_tests/package.json b/e2e_tests/package.json index 48b819dc..7ddd3a57 100644 --- a/e2e_tests/package.json +++ b/e2e_tests/package.json @@ -4,12 +4,14 @@ "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" + "@polkadot/api": "^11.0.2", + "@polkadot/keyring": "^12.6.2", + "typescript": "^5.4.5" } } diff --git a/e2e_tests/tsconfig.json b/e2e_tests/tsconfig.json new file mode 100644 index 00000000..e399350e --- /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" + ] + } \ No newline at end of file diff --git a/zombienet_tests/0002-native-fee-payment.zndsl b/zombienet_tests/0002-native-fee-payment.zndsl index e87c365e..7eaae633 100644 --- a/zombienet_tests/0002-native-fee-payment.zndsl +++ b/zombienet_tests/0002-native-fee-payment.zndsl @@ -7,4 +7,4 @@ bob: is up alice: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/fee-payment/native.js return is 0 within 200 seconds +regionx-collator01: js-script ../e2e_tests/build/fee-payment/native.js return is 0 within 200 seconds diff --git a/zombienet_tests/0003-custom-fee-payment.zndsl b/zombienet_tests/0003-custom-fee-payment.zndsl index 3ed50752..75ec1d28 100644 --- a/zombienet_tests/0003-custom-fee-payment.zndsl +++ b/zombienet_tests/0003-custom-fee-payment.zndsl @@ -7,4 +7,4 @@ rococo-validator02: is up rococo-validator01: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/fee-payment/custom.js return is 0 within 400 seconds +regionx-collator01: js-script ../e2e_tests/build/fee-payment/custom.js return is 0 within 400 seconds diff --git a/zombienet_tests/0004-delegated-governance.zndsl b/zombienet_tests/0004-delegated-governance.zndsl index f81632ce..4c63880c 100644 --- a/zombienet_tests/0004-delegated-governance.zndsl +++ b/zombienet_tests/0004-delegated-governance.zndsl @@ -7,4 +7,4 @@ rococo-validator02: is up rococo-validator01: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/governance/delegated.js return is 0 within 400 seconds +regionx-collator01: js-script ../e2e_tests/build/governance/delegated.js return is 0 within 400 seconds diff --git a/zombienet_tests/0005-native-governance.zndsl b/zombienet_tests/0005-native-governance.zndsl index 896b4767..3830e72c 100644 --- a/zombienet_tests/0005-native-governance.zndsl +++ b/zombienet_tests/0005-native-governance.zndsl @@ -7,4 +7,4 @@ rococo-validator02: is up rococo-validator01: parachain 2000 is registered within 225 seconds -regionx-collator01: js-script ../e2e_tests/governance/native.js return is 0 within 400 seconds +regionx-collator01: js-script ../e2e_tests/build/governance/native.js return is 0 within 400 seconds