diff --git a/Cargo.lock b/Cargo.lock index 9d6bb0235..65dc9d93e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1453,9 +1453,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.8" +version = "4.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272" dependencies = [ "clap_builder", "clap_derive", @@ -1463,9 +1463,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1" dependencies = [ "anstream", "anstyle", diff --git a/container-chains/templates/frontier/node/src/rpc/mod.rs b/container-chains/templates/frontier/node/src/rpc/mod.rs index d8545b500..b227b48cc 100644 --- a/container-chains/templates/frontier/node/src/rpc/mod.rs +++ b/container-chains/templates/frontier/node/src/rpc/mod.rs @@ -23,11 +23,9 @@ pub use sc_rpc::{DenyUnsafe, SubscriptionTaskExecutor}; -use sp_consensus_aura::SlotDuration; use { container_chain_template_frontier_runtime::{opaque::Block, AccountId, Hash, Index}, - cumulus_primitives_core::ParaId, - cumulus_primitives_core::PersistedValidationData, + cumulus_primitives_core::{ParaId, PersistedValidationData}, cumulus_primitives_parachain_inherent::ParachainInherentData, cumulus_test_relay_sproof_builder::RelayStateSproofBuilder, fc_rpc::{EthTask, TxPool}, @@ -52,6 +50,7 @@ use { sp_blockchain::{ Backend as BlockchainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, }, + sp_consensus_aura::SlotDuration, sp_core::H256, sp_runtime::traits::{BlakeTwo256, Block as BlockT}, std::{sync::Arc, time::Duration}, diff --git a/container-chains/templates/frontier/runtime/src/lib.rs b/container-chains/templates/frontier/runtime/src/lib.rs index 1ee081108..55cdc829d 100644 --- a/container-chains/templates/frontier/runtime/src/lib.rs +++ b/container-chains/templates/frontier/runtime/src/lib.rs @@ -563,6 +563,12 @@ impl Default for ProxyType { impl InstanceFilter for ProxyType { fn filter(&self, c: &RuntimeCall) -> bool { + // Since proxy filters are respected in all dispatches of the Utility + // pallet, it should never need to be filtered by any proxy. + if let RuntimeCall::Utility(..) = c { + return true; + } + match self { ProxyType::Any => true, ProxyType::NonTransfer => { @@ -571,17 +577,17 @@ impl InstanceFilter for ProxyType { RuntimeCall::System(..) | RuntimeCall::ParachainSystem(..) | RuntimeCall::Timestamp(..) - | RuntimeCall::Utility(..) | RuntimeCall::Proxy(..) ) } - ProxyType::Governance => matches!(c, RuntimeCall::Utility(..)), + // We don't have governance yet + ProxyType::Governance => false, ProxyType::CancelProxy => matches!( c, RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) ), ProxyType::Balances => { - matches!(c, RuntimeCall::Balances(..) | RuntimeCall::Utility(..)) + matches!(c, RuntimeCall::Balances(..)) } } } diff --git a/container-chains/templates/simple/runtime/src/lib.rs b/container-chains/templates/simple/runtime/src/lib.rs index a7bbbe557..a409bd7b8 100644 --- a/container-chains/templates/simple/runtime/src/lib.rs +++ b/container-chains/templates/simple/runtime/src/lib.rs @@ -449,6 +449,12 @@ impl Default for ProxyType { impl InstanceFilter for ProxyType { fn filter(&self, c: &RuntimeCall) -> bool { + // Since proxy filters are respected in all dispatches of the Utility + // pallet, it should never need to be filtered by any proxy. + if let RuntimeCall::Utility(..) = c { + return true; + } + match self { ProxyType::Any => true, ProxyType::NonTransfer => { @@ -457,17 +463,17 @@ impl InstanceFilter for ProxyType { RuntimeCall::System(..) | RuntimeCall::ParachainSystem(..) | RuntimeCall::Timestamp(..) - | RuntimeCall::Utility(..) | RuntimeCall::Proxy(..) ) } - ProxyType::Governance => matches!(c, RuntimeCall::Utility(..)), + // We don't have governance yet + ProxyType::Governance => false, ProxyType::CancelProxy => matches!( c, RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) ), ProxyType::Balances => { - matches!(c, RuntimeCall::Balances(..) | RuntimeCall::Utility(..)) + matches!(c, RuntimeCall::Balances(..)) } } } diff --git a/pallets/registrar/src/lib.rs b/pallets/registrar/src/lib.rs index 84174cd8c..3dc3d8b38 100644 --- a/pallets/registrar/src/lib.rs +++ b/pallets/registrar/src/lib.rs @@ -251,8 +251,7 @@ pub mod pallet { impl Hooks> for Pallet { #[cfg(feature = "try-runtime")] fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { - use scale_info::prelude::format; - use sp_std::collections::btree_set::BTreeSet; + use {scale_info::prelude::format, sp_std::collections::btree_set::BTreeSet}; // A para id can only be in 1 of [`RegisteredParaIds`, `PendingVerification`, `Paused`] // Get all those para ids and check for duplicates let mut para_ids: Vec = vec![]; @@ -604,10 +603,10 @@ pub mod pallet { #[cfg(feature = "runtime-benchmarks")] pub fn benchmarks_get_or_create_para_manager(para_id: &ParaId) -> Result { - use frame_benchmarking::account; - use frame_support::assert_ok; - use frame_support::dispatch::RawOrigin; - use frame_support::traits::Currency; + use { + frame_benchmarking::account, + frame_support::{assert_ok, dispatch::RawOrigin, traits::Currency}, + }; // Return container chain manager, or register container chain as ALICE if it does not exist if !ParaGenesisData::::contains_key(para_id) { // Register as a new user diff --git a/runtime/dancebox/src/lib.rs b/runtime/dancebox/src/lib.rs index d4a342300..6074cb996 100644 --- a/runtime/dancebox/src/lib.rs +++ b/runtime/dancebox/src/lib.rs @@ -36,7 +36,6 @@ pub mod weights; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; -use frame_support::traits::EitherOfDiverse; use { cumulus_pallet_parachain_system::{RelayChainStateProof, RelayNumberStrictlyIncreases}, cumulus_primitives_core::{ @@ -50,8 +49,8 @@ use { parameter_types, traits::{ fungible::{Balanced, Credit}, - ConstU128, ConstU32, ConstU64, ConstU8, Contains, InsideBoth, InstanceFilter, - OffchainWorker, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, + ConstU128, ConstU32, ConstU64, ConstU8, Contains, EitherOfDiverse, InsideBoth, + InstanceFilter, OffchainWorker, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, ValidatorRegistration, }, weights::{ @@ -937,6 +936,10 @@ pub enum ProxyType { CancelProxy = 4, /// Allow extrinsic related to Balances. Balances = 5, + /// Allow extrinsics related to Registrar + Registrar = 6, + /// Allow extrinsics related to Registrar that needs to be called through Sudo + SudoRegistrar = 7, } impl Default for ProxyType { @@ -947,6 +950,12 @@ impl Default for ProxyType { impl InstanceFilter for ProxyType { fn filter(&self, c: &RuntimeCall) -> bool { + // Since proxy filters are respected in all dispatches of the Utility + // pallet, it should never need to be filtered by any proxy. + if let RuntimeCall::Utility(..) = c { + return true; + } + match self { ProxyType::Any => true, ProxyType::NonTransfer => { @@ -955,25 +964,37 @@ impl InstanceFilter for ProxyType { RuntimeCall::System(..) | RuntimeCall::ParachainSystem(..) | RuntimeCall::Timestamp(..) - | RuntimeCall::Utility(..) | RuntimeCall::Proxy(..) | RuntimeCall::Registrar(..) ) } - ProxyType::Governance => matches!(c, RuntimeCall::Utility(..)), - ProxyType::Staking => matches!( - c, - RuntimeCall::Session(..) - | RuntimeCall::Utility(..) - | RuntimeCall::PooledStaking(..) - ), + // We don't have governance yet + ProxyType::Governance => false, + ProxyType::Staking => { + matches!(c, RuntimeCall::Session(..) | RuntimeCall::PooledStaking(..)) + } ProxyType::CancelProxy => matches!( c, RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) ), ProxyType::Balances => { - matches!(c, RuntimeCall::Balances(..) | RuntimeCall::Utility(..)) + matches!(c, RuntimeCall::Balances(..)) } + ProxyType::Registrar => { + matches!( + c, + RuntimeCall::Registrar(..) | RuntimeCall::DataPreservers(..) + ) + } + ProxyType::SudoRegistrar => match c { + RuntimeCall::Sudo(pallet_sudo::Call::sudo { call: ref x }) => { + matches!( + x.as_ref(), + &RuntimeCall::Registrar(..) | &RuntimeCall::DataPreservers(..) + ) + } + _ => false, + }, } } diff --git a/runtime/dancebox/src/migrations.rs b/runtime/dancebox/src/migrations.rs index 0900ebd37..60a2ef561 100644 --- a/runtime/dancebox/src/migrations.rs +++ b/runtime/dancebox/src/migrations.rs @@ -22,8 +22,12 @@ use { crate::{Invulnerables, ParaId, Runtime, RuntimeOrigin, ServicesPayment, LOG_TARGET}, frame_support::{ - migration::storage_key_iter, pallet_prelude::ValueQuery, storage::types::StorageMap, - storage::types::StorageValue, traits::OnRuntimeUpgrade, weights::Weight, Blake2_128Concat, + migration::storage_key_iter, + pallet_prelude::ValueQuery, + storage::types::{StorageMap, StorageValue}, + traits::OnRuntimeUpgrade, + weights::Weight, + Blake2_128Concat, }, pallet_balances::IdAmount, pallet_configuration::{weights::WeightInfo as _, HostConfiguration}, diff --git a/runtime/dancebox/tests/common/mod.rs b/runtime/dancebox/tests/common/mod.rs index e198c1a55..a88cc877a 100644 --- a/runtime/dancebox/tests/common/mod.rs +++ b/runtime/dancebox/tests/common/mod.rs @@ -201,6 +201,8 @@ pub struct ExtBuilder { balances: Vec<(AccountId, Balance)>, // [collator, amount] collators: Vec<(AccountId, Balance)>, + // sudo key + sudo: Option, // list of registered para ids: para_id, genesis_data, boot_nodes, block_credits para_ids: Vec<( u32, @@ -225,6 +227,11 @@ impl ExtBuilder { self } + pub fn with_sudo(mut self, sudo: AccountId) -> Self { + self.sudo = Some(sudo); + self + } + pub fn with_para_ids( mut self, para_ids: Vec<( @@ -347,6 +354,10 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); } + pallet_sudo::GenesisConfig:: { key: self.sudo } + .assimilate_storage(&mut t) + .unwrap(); + t } diff --git a/runtime/dancebox/tests/integration_test.rs b/runtime/dancebox/tests/integration_test.rs index d6c6b061e..335afcd9f 100644 --- a/runtime/dancebox/tests/integration_test.rs +++ b/runtime/dancebox/tests/integration_test.rs @@ -2307,6 +2307,86 @@ fn test_proxy_non_transfer() { }); } +#[test] +fn test_proxy_utility() { + // All proxy types should be able to use Utility pallet, but we ensure + // subcalls don't allow to circumvent filters. + + // Dummy match to ensure we update this test when adding new proxy types. + match ProxyType::Any { + ProxyType::Any + | ProxyType::NonTransfer + | ProxyType::Governance + | ProxyType::Staking + | ProxyType::CancelProxy + | ProxyType::Balances + | ProxyType::Registrar + | ProxyType::SudoRegistrar => (), + }; + + // All except for any + let proxy_types = &[ + ProxyType::NonTransfer, + ProxyType::Governance, + ProxyType::Staking, + ProxyType::CancelProxy, + ProxyType::Balances, + ProxyType::Registrar, + ProxyType::SudoRegistrar, + ]; + + for &proxy_type in proxy_types { + ExtBuilder::default() + .with_balances(vec![ + // Alice gets 10k extra tokens for her mapping deposit + (AccountId::from(ALICE), 210_000 * UNIT), + (AccountId::from(BOB), 100_000 * UNIT), + (AccountId::from(CHARLIE), 100_000 * UNIT), + (AccountId::from(DAVE), 100_000 * UNIT), + ]) + .with_collators(vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ]) + .with_sudo(AccountId::from(ALICE)) + .with_config(default_config()) + .build() + .execute_with(|| { + assert_ok!(Proxy::add_proxy( + origin_of(ALICE.into()), + AccountId::from(BOB).into(), + proxy_type, + 0 + )); + + let free_balance = Balances::free_balance(AccountId::from(BOB)); + + assert_ok!(Proxy::proxy( + origin_of(BOB.into()), + AccountId::from(ALICE).into(), + None, + Box::new( + pallet_sudo::Call::sudo { + call: Box::new( + pallet_utility::Call::batch { + calls: vec![pallet_balances::Call::force_set_balance { + who: AccountId::from(BOB).into(), + new_free: 42424242424242 + } + .into()] + } + .into() + ) + } + .into() + ) + )); + + assert_eq!(Balances::free_balance(AccountId::from(BOB)), free_balance); + }); + } +} + #[test] fn check_well_known_keys() { use frame_support::traits::PalletInfo; diff --git a/test/suites/dev-tanssi/registrar/test_registrar_proxy.ts b/test/suites/dev-tanssi/registrar/test_registrar_proxy.ts new file mode 100644 index 000000000..b9c38b9be --- /dev/null +++ b/test/suites/dev-tanssi/registrar/test_registrar_proxy.ts @@ -0,0 +1,205 @@ +import "@tanssi/api-augment"; +import { describeSuite, expect, beforeAll } from "@moonwall/cli"; +import { KeyringPair } from "@moonwall/util"; +import { ApiPromise } from "@polkadot/api"; +import { jumpSessions } from "util/block"; + +describeSuite({ + id: "DT0605", + title: "Registrar test suite", + foundationMethods: "dev", + testCases: ({ it, context }) => { + let polkadotJs: ApiPromise; + let alice: KeyringPair; + let bob: KeyringPair; + let charlie: KeyringPair; + + beforeAll(() => { + alice = context.keyring.alice; + bob = context.keyring.bob; + charlie = context.keyring.charlie; + polkadotJs = context.polkadotJs(); + }); + + it({ + id: "E01", + title: "Can add registrar proxy and use it", + test: async function () { + // Setup proxy + const delegate = charlie.address; + const registrar_proxy = 6; + const delay = 0; + const tx = polkadotJs.tx.proxy.addProxy(delegate, registrar_proxy, delay); + await context.createBlock([await tx.signAsync(bob)]); + + const events = await polkadotJs.query.system.events(); + const ev1 = events.filter((a) => { + return a.event.method == "ProxyAdded"; + }); + expect(ev1.length).to.be.equal(1); + + const proxies = await polkadotJs.query.proxy.proxies(bob.address); + expect(proxies.toJSON()[0]).to.deep.equal([ + { + delegate: charlie.address, + proxyType: "Registrar", + delay: 0, + }, + ]); + + // Use proxy + await context.createBlock(); + + const emptyGenesisData = () => { + const g = polkadotJs.createType("TpContainerChainGenesisDataContainerChainGenesisData", { + storage: [ + { + key: "0x636f6465", + value: "0x010203040506", + }, + ], + name: "0x436f6e7461696e657220436861696e2032303030", + id: "0x636f6e7461696e65722d636861696e2d32303030", + forkId: null, + extensions: "0x", + properties: { + tokenMetadata: { + tokenSymbol: "0x61626364", + ss58Format: 42, + tokenDecimals: 12, + }, + isEthereum: false, + }, + }); + return g; + }; + const containerChainGenesisData = emptyGenesisData(); + + // assert we can inject on chain data with proxy + const tx2 = polkadotJs.tx.proxy.proxy( + bob.address, + null, + polkadotJs.tx.registrar.register(2002, containerChainGenesisData) + ); + await context.createBlock([await tx2.signAsync(charlie)]); + // Check that the on chain genesis data is set correctly + const onChainGenesisData = await polkadotJs.query.registrar.paraGenesisData(2002); + // TODO: fix once we have types + expect(emptyGenesisData().toJSON()).to.deep.equal(onChainGenesisData.toJSON()); + + // assert we can inject bootnodes with proxy + const tx3 = polkadotJs.tx.proxy.proxy( + bob.address, + null, + polkadotJs.tx.dataPreservers.setBootNodes(2002, ["dummy"]) + ); + await context.createBlock([await tx3.signAsync(charlie)]); + + // Check that the on chain genesis data is set correctly + const onChainBootnodes = await polkadotJs.query.dataPreservers.bootNodes(2002); + // TODO: fix once we have types + expect(onChainBootnodes.toHuman()).to.deep.equal(["dummy"]); + }, + }); + + it({ + id: "E02", + title: "SudoRegistrar proxy works", + test: async function () { + // Proxy + const delegate = charlie.address; + const sudo_registrar_proxy = 7; + const delay = 0; + const tx = polkadotJs.tx.proxy.addProxy(delegate, sudo_registrar_proxy, delay); + await context.createBlock(); + await context.createBlock([await tx.signAsync(alice)]); + + const events = await polkadotJs.query.system.events(); + const ev1 = events.filter((a) => { + return a.event.method == "ProxyAdded"; + }); + expect(ev1.length).to.be.equal(1); + + const proxies = await polkadotJs.query.proxy.proxies(alice.address); + expect(proxies.toJSON()[0]).to.deep.equal([ + { + delegate: charlie.address, + proxyType: "SudoRegistrar", + delay: 0, + }, + ]); + + // Registrar + await context.createBlock(); + + const currentSesssion = await polkadotJs.query.session.currentIndex(); + const sessionDelay = await polkadotJs.consts.registrar.sessionDelay; + const expectedScheduledOnboarding = + BigInt(currentSesssion.toString()) + BigInt(sessionDelay.toString()); + + const emptyGenesisData = () => { + const g = polkadotJs.createType("TpContainerChainGenesisDataContainerChainGenesisData", { + storage: [ + { + key: "0x636f6465", + value: "0x010203040506", + }, + ], + name: "0x436f6e7461696e657220436861696e2032303030", + id: "0x636f6e7461696e65722d636861696e2d32303030", + forkId: null, + extensions: "0x", + properties: { + tokenMetadata: { + tokenSymbol: "0x61626364", + ss58Format: 42, + tokenDecimals: 12, + }, + isEthereum: false, + }, + }); + return g; + }; + const containerChainGenesisData = emptyGenesisData(); + + const tx2 = polkadotJs.tx.registrar.register(2002, containerChainGenesisData); + const tx3 = polkadotJs.tx.registrar.markValidForCollating(2002); + const nonce = await polkadotJs.rpc.system.accountNextIndex(alice.publicKey); + await context.createBlock([ + await tx2.signAsync(alice, { nonce }), + await polkadotJs.tx.proxy + .proxy(alice.address, null, polkadotJs.tx.sudo.sudo(tx3)) + .signAsync(charlie), + ]); + + const pendingParas = await polkadotJs.query.registrar.pendingParaIds(); + expect(pendingParas.length).to.be.eq(1); + const sessionScheduling = pendingParas[0][0]; + const parasScheduled = pendingParas[0][1]; + + expect(sessionScheduling.toBigInt()).to.be.eq(expectedScheduledOnboarding); + + // These will be the paras in session 2 + // TODO: fix once we have types + expect(parasScheduled.toJSON()).to.deep.equal([2000, 2001, 2002]); + + // Check that the on chain genesis data is set correctly + const onChainGenesisData = await polkadotJs.query.registrar.paraGenesisData(2002); + // TODO: fix once we have types + expect(emptyGenesisData().toJSON()).to.deep.equal(onChainGenesisData.toJSON()); + + // Check the para id has been given some free credits + const credits = (await polkadotJs.query.servicesPayment.blockProductionCredits(2002)).toJSON(); + expect(credits, "Container chain 2002 should have been given credits").toBeGreaterThan(0); + + // Checking that in session 2 paras are registered + await jumpSessions(context, 2); + + // Expect now paraIds to be registered + const parasRegistered = await polkadotJs.query.registrar.registeredParaIds(); + // TODO: fix once we have types + expect(parasRegistered.toJSON()).to.deep.equal([2000, 2001, 2002]); + }, + }); + }, +}); diff --git a/typescript-api/src/dancebox/interfaces/augment-api-tx.ts b/typescript-api/src/dancebox/interfaces/augment-api-tx.ts index 33b48f80d..684704b4e 100644 --- a/typescript-api/src/dancebox/interfaces/augment-api-tx.ts +++ b/typescript-api/src/dancebox/interfaces/augment-api-tx.ts @@ -518,6 +518,8 @@ declare module "@polkadot/api-base/types/submittable" { | "Staking" | "CancelProxy" | "Balances" + | "Registrar" + | "SudoRegistrar" | number | Uint8Array, delay: u32 | AnyNumber | Uint8Array @@ -551,6 +553,8 @@ declare module "@polkadot/api-base/types/submittable" { | "Staking" | "CancelProxy" | "Balances" + | "Registrar" + | "SudoRegistrar" | number | Uint8Array, delay: u32 | AnyNumber | Uint8Array, @@ -578,6 +582,8 @@ declare module "@polkadot/api-base/types/submittable" { | "Staking" | "CancelProxy" | "Balances" + | "Registrar" + | "SudoRegistrar" | number | Uint8Array, index: u16 | AnyNumber | Uint8Array, @@ -609,6 +615,8 @@ declare module "@polkadot/api-base/types/submittable" { | "Staking" | "CancelProxy" | "Balances" + | "Registrar" + | "SudoRegistrar" | number, call: Call | IMethod | string | Uint8Array ) => SubmittableExtrinsic, @@ -646,6 +654,8 @@ declare module "@polkadot/api-base/types/submittable" { | "Staking" | "CancelProxy" | "Balances" + | "Registrar" + | "SudoRegistrar" | number, call: Call | IMethod | string | Uint8Array ) => SubmittableExtrinsic, @@ -705,6 +715,8 @@ declare module "@polkadot/api-base/types/submittable" { | "Staking" | "CancelProxy" | "Balances" + | "Registrar" + | "SudoRegistrar" | number | Uint8Array, delay: u32 | AnyNumber | Uint8Array diff --git a/typescript-api/src/dancebox/interfaces/lookup.ts b/typescript-api/src/dancebox/interfaces/lookup.ts index 6bf39763d..fd7def731 100644 --- a/typescript-api/src/dancebox/interfaces/lookup.ts +++ b/typescript-api/src/dancebox/interfaces/lookup.ts @@ -229,7 +229,7 @@ export default { }, /** Lookup38: dancebox_runtime::ProxyType */ DanceboxRuntimeProxyType: { - _enum: ["Any", "NonTransfer", "Governance", "Staking", "CancelProxy", "Balances"], + _enum: ["Any", "NonTransfer", "Governance", "Staking", "CancelProxy", "Balances", "Registrar", "SudoRegistrar"], }, /** Lookup40: pallet_migrations::pallet::Event */ PalletMigrationsEvent: { diff --git a/typescript-api/src/dancebox/interfaces/types-lookup.ts b/typescript-api/src/dancebox/interfaces/types-lookup.ts index a01eac064..c3ce9b60b 100644 --- a/typescript-api/src/dancebox/interfaces/types-lookup.ts +++ b/typescript-api/src/dancebox/interfaces/types-lookup.ts @@ -348,7 +348,17 @@ declare module "@polkadot/types/lookup" { readonly isStaking: boolean; readonly isCancelProxy: boolean; readonly isBalances: boolean; - readonly type: "Any" | "NonTransfer" | "Governance" | "Staking" | "CancelProxy" | "Balances"; + readonly isRegistrar: boolean; + readonly isSudoRegistrar: boolean; + readonly type: + | "Any" + | "NonTransfer" + | "Governance" + | "Staking" + | "CancelProxy" + | "Balances" + | "Registrar" + | "SudoRegistrar"; } /** @name PalletMigrationsEvent (40) */