diff --git a/Cargo.lock b/Cargo.lock index 33a261ac4a8a..cba8f5564c3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12331,17 +12331,25 @@ dependencies = [ "frame-system", "log", "pallet-balances", + "pallet-message-queue", "pallet-nfts", + "pallet-xcm", "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-parachains", "scale-info", "serde", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-std 14.0.0", + "sp-tracing 16.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", + "staging-xcm-executor", + "xcm-simulator", ] [[package]] diff --git a/templates/parachain/pallets/xcnft/Cargo.toml b/templates/parachain/pallets/xcnft/Cargo.toml index 3f979a0ccfe1..7dc6a4a7b0af 100644 --- a/templates/parachain/pallets/xcnft/Cargo.toml +++ b/templates/parachain/pallets/xcnft/Cargo.toml @@ -28,7 +28,6 @@ frame-system = { workspace = true } #XCM xcm = { workspace = true} -xcm-builder = { workspace = true, default-features = false } cumulus-primitives-core = { workspace = true } cumulus-pallet-xcm = { workspace = true } @@ -49,8 +48,16 @@ sp-io = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } - - +# For unit tests +xcm-builder = { workspace = true, default-features = true } +xcm-simulator = { workspace = true, default-features = true } +xcm-executor = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } +pallet-xcm = { workspace = true, default-features = true } +polkadot-core-primitives = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true, default-features = true } [features] default = [ "std" ] @@ -63,6 +70,11 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-nfts/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-runtime-parachains/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", ] std = [ "codec/std", diff --git a/templates/parachain/pallets/xcnft/src/file b/templates/parachain/pallets/xcnft/src/file new file mode 100644 index 000000000000..266aa9673940 --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/file @@ -0,0 +1,1139 @@ + + + + + + + + + +use crate::{ + mock::*, Error, Event, GeneralizedDestroyWitness, Proposal, ReceivedAssets, + ReceivedCollections, ReceivedCols, ReceivedStruct, SentAssets, SentStruct, +}; + +pub mod testpara; +pub mod testrelay; + +use frame_support::assert_noop; +use pallet_nfts::{CollectionConfigFor, CollectionSettings, Event::Destroyed, MintSettings}; +use sp_runtime::{AccountId32, BoundedVec}; + +pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub const BOB: AccountId32 = AccountId32::new([1u8; 32]); +pub const INITIAL_BALANCE: u128 = 1_000_000_000; + +use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; +use sp_tracing; + +pub fn parent_account_id() -> testpara::AccountId { + let location = (Parent,); + testpara::location_converter::LocationConverter::convert_location(&location.into()).unwrap() +} + +pub fn child_account_id(para: u32) -> testrelay::AccountId { + let location = (Parachain(para),); + testrelay::location_converter::LocationConverter::convert_location(&location.into()).unwrap() +} + +decl_test_parachain! { + pub struct ParaA { + Runtime = testpara::Runtime, + XcmpMessageHandler = testpara::MsgQueue, + DmpMessageHandler = testpara::MsgQueue, + new_ext = para_ext(1), + } +} + +decl_test_parachain! { + pub struct ParaB { + Runtime = testpara::Runtime, + XcmpMessageHandler = testpara::MsgQueue, + DmpMessageHandler = testpara::MsgQueue, + new_ext = para_ext(2), + } +} + +decl_test_relay_chain! { + pub struct Relay { + Runtime = testrelay::Runtime, + RuntimeCall = testrelay::RuntimeCall, + RuntimeEvent = testrelay::RuntimeEvent, + XcmConfig = testrelay::XcmConfig, + MessageQueue = testrelay::MessageQueue, + System = testrelay::System, + new_ext = relay_ext(), + } +} + +decl_test_network! { + pub struct MockNet { + relay_chain = Relay, + parachains = vec![ + (1, ParaA), + (2, ParaB), + ], + } +} + + + +pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { + use testpara::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(ALICE, INITIAL_BALANCE), (parent_account_id(), INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + sp_tracing::try_init_simple(); + System::set_block_number(1); + MsgQueue::set_para_id(para_id.into()); + }); + ext +} + +pub fn relay_ext() -> sp_io::TestExternalities { + use testrelay::{Runtime, RuntimeOrigin, System, NFTs}; + + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + (ALICE, INITIAL_BALANCE), + (child_account_id(1), INITIAL_BALANCE), + (child_account_id(2), INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + }); + ext +} + +#[test] +fn try_sending_collection_that_doesnt_exist() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + const COLLECTION_ID: u32 = 1; + + assert_noop!( + XcNFT::collection_x_transfer( + RuntimeOrigin::signed(ALICE), + COLLECTION_ID, + Some(COLLECTION_ID), + 2000.into(), + None + ), + Error::::CollectionDoesNotExist + ); + }); +} + +#[test] +fn try_sending_collection_that_user_doesnt_own() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + const COLLECTION_ID: u32 = 1; + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + assert_noop!( + XcNFT::collection_x_transfer( + RuntimeOrigin::signed(BOB), + 0, + Some(COLLECTION_ID), + 2000.into(), + None + ), + Error::::NotCollectionOwner + ); + }); +} + +#[test] +fn try_voting_on_non_existing_proposal() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + + assert_noop!( + XcNFT::collection_x_transfer_vote(RuntimeOrigin::signed(ALICE), 0, crate::Vote::Aye), + Error::::ProposalDoesNotExist + ); + }); +} + +#[test] +fn try_voting_on_proposal_when_no_owner() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + const COLLECTION_ID: u32 = 1; + + //Create proposal + let proposal = Proposal:: { + proposal_id: 1, + collection_id: COLLECTION_ID, + proposed_collection_owner: ALICE, + proposed_destination_para: 2000.into(), + proposed_dest_collection_id: None, + proposed_destination_config: None, + owners: BoundedVec::new(), + number_of_votes: crate::Votes { aye: BoundedVec::new(), nay: BoundedVec::new() }, + end_time: 20u64.into(), + }; + + let _ = crate::CrossChainProposals::insert(1, proposal); + + assert_noop!( + XcNFT::collection_x_transfer_vote(RuntimeOrigin::signed(BOB), 1, crate::Vote::Aye), + Error::::NotNFTOwner + ); + }); +} + +#[test] +fn try_voting_on_proposal_expired() { + new_test_ext().execute_with(|| { + System::set_block_number(3); + const COLLECTION_ID: u32 = 1; + + //Create owners vector + let mut owners = BoundedVec::new(); + owners.try_push(ALICE).expect("Failed to push owner"); + + //Create proposal + let proposal = Proposal:: { + proposal_id: 1, + collection_id: COLLECTION_ID, + proposed_collection_owner: ALICE, + proposed_destination_para: 2000.into(), + proposed_dest_collection_id: None, + proposed_destination_config: None, + owners: owners.clone(), + number_of_votes: crate::Votes { aye: owners.clone(), nay: BoundedVec::new() }, + end_time: 1u64.into(), + }; + + let _ = crate::CrossChainProposals::insert(1, proposal); + + let _ = + XcNFT::collection_x_transfer_vote(RuntimeOrigin::signed(ALICE), 1, crate::Vote::Aye); + + System::assert_last_event(RuntimeEvent::XcNFT(Event::ProposalExpired { proposal_id: 1 })); + }); +} + +#[test] +fn try_voting_on_proposal_did_not_pass() { + new_test_ext().execute_with(|| { + System::set_block_number(3); + const COLLECTION_ID: u32 = 1; + + //Create owners vector + let mut owners = BoundedVec::new(); + owners.try_push(ALICE).expect("Failed to push owner"); + + //Create proposal + let proposal = Proposal:: { + proposal_id: 1, + collection_id: COLLECTION_ID, + proposed_collection_owner: ALICE, + proposed_destination_para: 2000.into(), + proposed_dest_collection_id: None, + proposed_destination_config: None, + owners: owners.clone(), + number_of_votes: crate::Votes { aye: BoundedVec::new(), nay: owners.clone() }, + end_time: 1u64.into(), + }; + + let _ = crate::CrossChainProposals::insert(1, proposal); + + let _ = + XcNFT::collection_x_transfer_vote(RuntimeOrigin::signed(ALICE), 1, crate::Vote::Aye); + + System::assert_last_event(RuntimeEvent::XcNFT(Event::ProposalDidNotPass { + proposal_id: 1, + })); + }); +} + +#[test] +fn try_voting_on_proposal_again_same_vote() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + const COLLECTION_ID: u32 = 1; + + //Create owners vector + let mut owners = BoundedVec::new(); + owners.try_push(ALICE).expect("Failed to push owner"); + + //Create proposal + let proposal = Proposal:: { + proposal_id: 1, + collection_id: COLLECTION_ID, + proposed_collection_owner: ALICE, + proposed_destination_para: 2000.into(), + proposed_dest_collection_id: None, + proposed_destination_config: None, + owners: owners.clone(), + number_of_votes: crate::Votes { aye: BoundedVec::new(), nay: owners.clone() }, + end_time: 3u64.into(), + }; + + let _ = crate::CrossChainProposals::insert(1, proposal); + + let _ = + XcNFT::collection_x_transfer_vote(RuntimeOrigin::signed(ALICE), 1, crate::Vote::Aye); + + assert_noop!( + XcNFT::collection_x_transfer_vote(RuntimeOrigin::signed(ALICE), 1, crate::Vote::Aye), + Error::::AlreadyVotedThis + ); + }); +} + +#[test] +fn vote_on_proposal_successfuly() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + const COLLECTION_ID: u32 = 1; + + //Create owners vector + let mut owners = BoundedVec::new(); + owners.try_push(ALICE).expect("Failed to push owner"); + + //Create proposal + let proposal = Proposal:: { + proposal_id: 1, + collection_id: COLLECTION_ID, + proposed_collection_owner: ALICE, + proposed_destination_para: 2000.into(), + proposed_dest_collection_id: None, + proposed_destination_config: None, + owners: owners.clone(), + number_of_votes: crate::Votes { aye: BoundedVec::new(), nay: owners.clone() }, + end_time: 2u64.into(), + }; + + let _ = crate::CrossChainProposals::insert(1, proposal); + + let _ = + XcNFT::collection_x_transfer_vote(RuntimeOrigin::signed(ALICE), 1, crate::Vote::Aye); + + System::assert_last_event(RuntimeEvent::XcNFT(Event::CrossChainPropoposalVoteRegistered { + proposal_id: 1, + voter: ALICE, + vote: crate::Vote::Aye, + })); + }); +} + +#[test] +fn try_initiating_proposal_doesnt_exist() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + + assert_noop!( + XcNFT::collection_x_transfer_initiate(RuntimeOrigin::signed(ALICE), 1), + Error::::ProposalDoesNotExist + ); + }); +} + +#[test] +fn try_initiating_proposal_collection_doesnt_exist() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + + const COLLECTION_ID: u32 = 1; + + //Create owners vector + let mut owners = BoundedVec::new(); + owners.try_push(ALICE).expect("Failed to push owner"); + + //Create proposal + let proposal = Proposal:: { + proposal_id: 1, + collection_id: COLLECTION_ID, + proposed_collection_owner: ALICE, + proposed_destination_para: 2000.into(), + proposed_dest_collection_id: None, + proposed_destination_config: None, + owners: owners.clone(), + number_of_votes: crate::Votes { aye: BoundedVec::new(), nay: owners.clone() }, + end_time: 2u64.into(), + }; + + let _ = crate::CrossChainProposals::insert(1, proposal); + + assert_noop!( + XcNFT::collection_x_transfer_initiate(RuntimeOrigin::signed(ALICE), 1), + Error::::CollectionDoesNotExist + ); + }); +} + +#[test] +fn try_initiating_proposal_no_collection_owner() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(BOB), ALICE, def_config); + + //Create owners vector + let mut owners = BoundedVec::new(); + owners.try_push(BOB).expect("Failed to push owner"); + + //Create proposal + let proposal = Proposal:: { + proposal_id: 1, + collection_id: 0, + proposed_collection_owner: BOB, + proposed_destination_para: 2000.into(), + proposed_dest_collection_id: None, + proposed_destination_config: None, + owners: owners.clone(), + number_of_votes: crate::Votes { aye: BoundedVec::new(), nay: owners.clone() }, + end_time: 1u64.into(), + }; + + let _ = crate::CrossChainProposals::insert(1, proposal); + + assert_noop!( + XcNFT::collection_x_transfer_initiate(RuntimeOrigin::signed(ALICE), 1), + Error::::NotCollectionOwner + ); + }); +} + +#[test] +fn try_initiating_proposal_that_did_not_pass() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + //Create owners vector + let mut owners = BoundedVec::new(); + owners.try_push(ALICE).expect("Failed to push owner"); + + //Create proposal + let proposal = Proposal:: { + proposal_id: 1, + collection_id: 0, + proposed_collection_owner: ALICE, + proposed_destination_para: 2000.into(), + proposed_dest_collection_id: None, + proposed_destination_config: None, + owners: owners.clone(), + number_of_votes: crate::Votes { aye: BoundedVec::new(), nay: owners.clone() }, + end_time: 1u64.into(), + }; + + let _ = crate::CrossChainProposals::insert(1, proposal); + let _ = XcNFT::collection_x_transfer_initiate(RuntimeOrigin::signed(ALICE), 1); + + System::assert_has_event(RuntimeEvent::XcNFT(Event::ProposalDidNotPass { proposal_id: 1 })); + }); +} + +#[test] +fn try_sending_nft_no_collection() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + assert_noop!( + XcNFT::nft_x_transfer(RuntimeOrigin::signed(ALICE), 1, 0, 1000.into(), 1, 1), + Error::::CollectionDoesNotExist + ); + }); +} + +#[test] +fn try_sending_nft_no_nft() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + assert_noop!( + XcNFT::nft_x_transfer(RuntimeOrigin::signed(ALICE), 0, 0, 1000.into(), 1, 1), + Error::::NFTDoesNotExist + ); + }); +} + +#[test] +fn try_sending_nft_not_nft_owner() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + let _ = NFTs::mint(RuntimeOrigin::signed(ALICE), 0, 0, ALICE, None); + + assert_noop!( + XcNFT::nft_x_transfer(RuntimeOrigin::signed(BOB), 0, 0, 1000.into(), 1, 1), + Error::::NotNFTOwner + ); + }); +} + +#[test] +fn try_claiming_nft_no_collection() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + assert_noop!( + XcNFT::nft_x_claim(RuntimeOrigin::signed(ALICE), 1u32, 0u32, 100u32.into(), 1u32, 1u32), + Error::::CollectionDoesNotExist + ); + }); +} + +#[test] +fn try_claiming_nft_no_collection_origin() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + assert_noop!( + XcNFT::nft_x_claim(RuntimeOrigin::signed(ALICE), 1u32, 0u32, 100u32.into(), 1u32, 1u32), + Error::::CollectionDoesNotExist + ); + }); +} + +#[test] +fn try_claiming_nft_wrong_origin_collection() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + let collections: ReceivedCols = ReceivedCols:: { + origin_para_id: 1000.into(), + origin_collection_id: 10, + received_collection_id: 20, + }; + + let _ = ReceivedCollections::::insert(0, collections); + + assert_noop!( + XcNFT::nft_x_claim(RuntimeOrigin::signed(ALICE), 0u32, 0u32, 100u32.into(), 0u32, 1u32), + Error::::WrongOriginCollectionAtOrigin + ); + }); +} + +#[test] +fn try_claiming_nft_wrong_nft() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + let collections: ReceivedCols = ReceivedCols:: { + origin_para_id: 1000.into(), + origin_collection_id: 0, + received_collection_id: 0, + }; + + let _ = ReceivedCollections::::insert(0, collections); + + assert_noop!( + XcNFT::nft_x_claim(RuntimeOrigin::signed(ALICE), 0u32, 0u32, 100u32.into(), 0u32, 0u32), + Error::::NFTNotReceived + ); + }); +} + +#[test] +fn try_claiming_nft_not_owner() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + let _ = NFTs::mint(RuntimeOrigin::signed(ALICE), 0u32, 0u32, ALICE, None); + + System::set_block_number(3); + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + let _ = NFTs::mint(RuntimeOrigin::signed(ALICE), 1u32, 0u32, ALICE, None); + + let collections: ReceivedCols = ReceivedCols:: { + origin_para_id: 1000.into(), + origin_collection_id: 0, + received_collection_id: 0, + }; + + let _ = ReceivedCollections::::insert(0, collections); + + let nfts: ReceivedStruct = ReceivedStruct:: { + origin_para_id: 1000.into(), + origin_collection_id: 0, + origin_asset_id: 0, + received_collection_id: 1, + received_asset_id: 0, + }; + + let _ = ReceivedAssets::::insert((1, 0), nfts); + + assert_noop!( + XcNFT::nft_x_claim(RuntimeOrigin::signed(BOB), 0u32, 0u32, 0u32, 1u32, 0u32), + Error::::NotNFTOwner + ); + }); +} + +#[test] +fn try_claiming_nft_success() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + let _ = NFTs::mint(RuntimeOrigin::signed(ALICE), 0u32, 0u32, ALICE, None); + + System::set_block_number(3); + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + let _ = NFTs::mint(RuntimeOrigin::signed(ALICE), 1u32, 0u32, ALICE, None); + + let collections: ReceivedCols = ReceivedCols:: { + origin_para_id: 1000.into(), + origin_collection_id: 0, + received_collection_id: 0, + }; + + let _ = ReceivedCollections::::insert(0, collections); + + let nfts: ReceivedStruct = ReceivedStruct:: { + origin_para_id: 1000.into(), + origin_collection_id: 0, + origin_asset_id: 0, + received_collection_id: 1, + received_asset_id: 0, + }; + + let _ = ReceivedAssets::::insert((1, 0), nfts); + System::set_block_number(3); + + let _ = XcNFT::nft_x_claim(RuntimeOrigin::signed(ALICE), 0u32, 0u32, 0u32, 1u32, 0u32); + + System::assert_has_event(RuntimeEvent::XcNFT(Event::NFTClaimed { + collection_claimed_from: 1, + asset_removed: 0, + collection_claimed_to: 0, + asset_claimed: 0, + })); + }); +} + +#[test] +fn try_collection_parse_empty_successful() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let _ = XcNFT::parse_collection_empty( + RuntimeOrigin::signed(ALICE), + 1, + None, + BoundedVec::new(), + None, + ); + + System::assert_has_event(RuntimeEvent::XcNFT(Event::CollectionReceived { + origin_collection_id: 1, + received_collection_id: 1, + to_address: ALICE, + })); + }); +} + +#[test] +fn try_parse_collection_burn_successful() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let destroy_witness = + GeneralizedDestroyWitness { item_meta: 0, item_configs: 0, attributes: 0 }; + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + let _ = XcNFT::parse_collection_burn(RuntimeOrigin::signed(ALICE), 0, destroy_witness); + + System::assert_has_event(RuntimeEvent::NFTs(pallet_nfts::Event::Destroyed { + collection: 0, + })); + }); +} + +#[test] +fn try_parse_collection_metadata_successful() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + let _ = + XcNFT::parse_collection_metadata(RuntimeOrigin::signed(ALICE), 0, BoundedVec::new()); + + System::assert_has_event(RuntimeEvent::NFTs(pallet_nfts::Event::CollectionMetadataSet { + collection: 0, + data: BoundedVec::new(), + })); + }); +} + +#[test] +fn try_parse_collection_owner_successful() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + pallet_nfts::OwnershipAcceptance::::insert(BOB, 0); + + let _ = XcNFT::parse_collection_owner(RuntimeOrigin::signed(ALICE), BOB, 0); + + System::assert_has_event(RuntimeEvent::NFTs(pallet_nfts::Event::OwnerChanged { + collection: 0, + new_owner: BOB, + })); + }); +} + +#[test] +fn try_parse_nft_burn_successful() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + let _ = NFTs::mint(RuntimeOrigin::signed(ALICE), 0, 0, ALICE, None); + + let _ = XcNFT::parse_nft_burn(RuntimeOrigin::signed(ALICE), 0, 0); + + System::assert_has_event(RuntimeEvent::NFTs(pallet_nfts::Event::Burned { + collection: 0, + item: 0, + owner: ALICE, + })); + }); +} + +#[test] +fn try_parse_nft_metadata_successful() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + let _ = NFTs::mint(RuntimeOrigin::signed(ALICE), 0, 0, ALICE, None); + + let _ = XcNFT::parse_nft_metadata(RuntimeOrigin::signed(ALICE), 0, 0, BoundedVec::new()); + + System::assert_has_event(RuntimeEvent::NFTs(pallet_nfts::Event::ItemMetadataSet { + collection: 0, + item: 0, + data: BoundedVec::new(), + })); + }); +} + +#[test] +fn try_parse_nft_owner_successful() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + let _ = NFTs::mint(RuntimeOrigin::signed(ALICE), 0, 0, ALICE, None); + + let _ = XcNFT::parse_nft_owner(RuntimeOrigin::signed(ALICE), BOB, 0, 0); + + System::assert_has_event(RuntimeEvent::NFTs(pallet_nfts::Event::Transferred { + collection: 0, + item: 0, + from: ALICE, + to: BOB, + })); + }); +} + +#[test] +fn try_parse_nft_transfer_no_collection() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + assert_noop!( + XcNFT::parse_nft_transfer( + RuntimeOrigin::signed(ALICE), + 0, + 0, + BoundedVec::new(), + 0, + 0, + 1000.into() + ), + Error::::CollectionDoesNotExist + ); + }); +} + +#[test] +fn try_parse_nft_transfer_already_received() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + let _ = NFTs::mint(RuntimeOrigin::signed(ALICE), 0, 0, ALICE, None); + + let nfts: ReceivedStruct = ReceivedStruct:: { + origin_para_id: 1000.into(), + origin_collection_id: 0, + origin_asset_id: 0, + received_collection_id: 0, + received_asset_id: 0, + }; + + let _ = ReceivedAssets::::insert((0, 0), nfts); + + assert_noop!( + XcNFT::parse_nft_transfer( + RuntimeOrigin::signed(ALICE), + 0, + 0, + BoundedVec::new(), + 0, + 0, + 1000.into() + ), + Error::::NFTAlreadyReceived + ); + }); +} + +#[test] +fn try_parse_nft_transfer_not_collection_owner() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + let _ = NFTs::mint(RuntimeOrigin::signed(ALICE), 0, 0, ALICE, None); + + assert_noop!( + XcNFT::parse_nft_transfer( + RuntimeOrigin::signed(BOB), + 0, + 0, + BoundedVec::new(), + 0, + 0, + 1000.into() + ), + Error::::NotCollectionOwner + ); + }); +} + +#[test] +fn try_parse_nft_transfer_not_existing_nft() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + let _ = NFTs::mint(RuntimeOrigin::signed(ALICE), 0, 0, ALICE, None); + + assert_noop!( + XcNFT::parse_nft_transfer( + RuntimeOrigin::signed(ALICE), + 0, + 0, + BoundedVec::new(), + 0, + 0, + 1000.into() + ), + Error::::NFTExists + ); + }); +} + +#[test] +fn try_parse_nft_transfer_successful() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + let _ = XcNFT::parse_nft_transfer( + RuntimeOrigin::signed(ALICE), + 0, + 0, + BoundedVec::new(), + 0, + 0, + 1000.into(), + ); + System::assert_has_event(RuntimeEvent::XcNFT(Event::NFTReceived { + origin_collection_id: 0, + origin_asset_id: 0, + received_collection_id: 0, + received_asset_id: 0, + to_address: ALICE, + })); + }); +} + +#[test] +fn try_parse_nft_transfer_return_to_origin() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let _ = NFTs::create(RuntimeOrigin::signed(ALICE), ALICE, def_config); + + let sent = SentStruct:: { + origin_para_id: ParachainInfo::parachain_id(), + origin_collection_id: 0, + origin_asset_id: 0, + destination_collection_id: 0, + destination_asset_id: 0, + }; + + let _ = SentAssets::::insert((0, 0), sent); + + //Set parachain id to 1000 + ParachainInfo::parachain_id(); + + let _ = XcNFT::parse_nft_transfer( + RuntimeOrigin::signed(ALICE), + 0, + 0, + BoundedVec::new(), + 0, + 0, + ParachainInfo::parachain_id(), + ); + System::assert_has_event(RuntimeEvent::XcNFT(Event::NFTReturnedToOrigin { + returned_from_collection_id: 0, + returned_from_asset_id: 0, + to_address: ALICE, + })); + }); +} + +#[test] +fn parse_collection_same_owner_successful() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let mut nfts: Vec<(u32, BoundedVec)> = Vec::new(); + nfts.push((1, BoundedVec::new())); + + let _ = XcNFT::parse_collection_same_owner( + RuntimeOrigin::signed(ALICE), + Some(def_config), + BoundedVec::new(), + nfts.clone(), + 1000.into(), + 0, + None, + ); + System::assert_has_event(RuntimeEvent::XcNFT(Event::CollectionWithNftsReceived { + collection_id: 0, + items: nfts.clone(), + })); + }); +} + +#[test] +fn parse_collection_diff_nft_owners_successful() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + + let def_config: CollectionConfigFor = CollectionConfigFor:: { + settings: CollectionSettings::all_enabled(), // Default settings (all enabled) + max_supply: None, /* No maximum supply defined + * initially */ + mint_settings: MintSettings::default(), // Use default mint settings + }; + + let mut nfts: Vec<(u32, AccountId32, BoundedVec)> = Vec::new(); + nfts.push((1, BOB, BoundedVec::new())); + + let _ = XcNFT::parse_collection_diff_owners( + RuntimeOrigin::signed(ALICE), + Some(def_config), + BoundedVec::new(), + nfts.clone(), + 1000.into(), + 0, + None, + ); + System::assert_has_event(RuntimeEvent::XcNFT( + Event::CollectionWithNftsDiffOwnersReceived { collection_id: 0, items: nfts.clone() }, + )); + }); +} diff --git a/templates/parachain/pallets/xcnft/src/tests.rs b/templates/parachain/pallets/xcnft/src/tests.rs index e516cd7629a4..f742f6bf87c7 100644 --- a/templates/parachain/pallets/xcnft/src/tests.rs +++ b/templates/parachain/pallets/xcnft/src/tests.rs @@ -2,30 +2,116 @@ use crate::{ mock::*, Error, Event, GeneralizedDestroyWitness, Proposal, ReceivedAssets, ReceivedCollections, ReceivedCols, ReceivedStruct, SentAssets, SentStruct, }; + +pub mod testpara; +pub mod testrelay; + use frame_support::assert_noop; use pallet_nfts::{CollectionConfigFor, CollectionSettings, Event::Destroyed, MintSettings}; -use sp_runtime::{AccountId32, BoundedVec}; +use sp_runtime::{AccountId32, BoundedVec, BuildStorage}; +use cumulus_primitives_core::Parachain; +use xcm_executor::traits::ConvertLocation; +use xcm::prelude::*; pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); pub const BOB: AccountId32 = AccountId32::new([1u8; 32]); +pub const INITIAL_BALANCE: u128 = 1_000_000_000; -#[test] -fn try_sending_collection_that_doesnt_exist() { - new_test_ext().execute_with(|| { +use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; +use sp_tracing; + +pub fn parent_account_id() -> testpara::AccountId { + let location = (Parent,); + testpara::location_converter::LocationConverter::convert_location(&location.into()).unwrap() +} + +pub fn child_account_id(para: u32) -> testrelay::AccountId { + let location = (Parachain(para),); + testrelay::location_converter::LocationConverter::convert_location(&location.into()).unwrap() +} + +decl_test_parachain! { + pub struct ParaA { + Runtime = testpara::Runtime, + XcmpMessageHandler = testpara::MsgQueue, + DmpMessageHandler = testpara::MsgQueue, + new_ext = para_ext(1), + } +} + +decl_test_parachain! { + pub struct ParaB { + Runtime = testpara::Runtime, + XcmpMessageHandler = testpara::MsgQueue, + DmpMessageHandler = testpara::MsgQueue, + new_ext = para_ext(2), + } +} + +decl_test_relay_chain! { + pub struct Relay { + Runtime = testrelay::Runtime, + RuntimeCall = testrelay::RuntimeCall, + RuntimeEvent = testrelay::RuntimeEvent, + XcmConfig = testrelay::XcmConfig, + MessageQueue = testrelay::MessageQueue, + System = testrelay::System, + new_ext = relay_ext(), + } +} + +decl_test_network! { + pub struct MockNet { + relay_chain = Relay, + parachains = vec![ + (1, ParaA), + (2, ParaB), + ], + } +} + + + +pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { + use testpara::{MsgQueue, Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(ALICE, INITIAL_BALANCE), (parent_account_id(), INITIAL_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + sp_tracing::try_init_simple(); System::set_block_number(1); - const COLLECTION_ID: u32 = 1; + MsgQueue::set_para_id(para_id.into()); + }); + ext +} - assert_noop!( - XcNFT::collection_x_transfer( - RuntimeOrigin::signed(ALICE), - COLLECTION_ID, - Some(COLLECTION_ID), - 2000.into(), - None - ), - Error::::CollectionDoesNotExist - ); +pub fn relay_ext() -> sp_io::TestExternalities { + use testrelay::{Runtime, RuntimeOrigin, System, NFTs}; + + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + (ALICE, INITIAL_BALANCE), + (child_account_id(1), INITIAL_BALANCE), + (child_account_id(2), INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); }); + ext } #[test] diff --git a/templates/parachain/pallets/xcnft/src/tests/testpara.rs b/templates/parachain/pallets/xcnft/src/tests/testpara.rs new file mode 100644 index 000000000000..2841c6448468 --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testpara.rs @@ -0,0 +1,215 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Parachain runtime mock. + +mod xcm_config; +pub use xcm_config::*; + +use parachain_info; + +use core::marker::PhantomData; +use frame_support::{ + construct_runtime, derive_impl, parameter_types, + traits::{ConstU128, ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, Nothing}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, +}; +use frame_support::pallet_prelude::Get; +use frame_system::{EnsureRoot, EnsureSigned}; +use sp_core::ConstU32; +use sp_runtime::{ + traits::{ConstU64, Verify, IdentityLookup}, + AccountId32, BuildStorage, MultiSignature, +}; +use xcm::latest::prelude::*; +use xcm_builder::{EnsureXcmOrigin, SignedToAccountId32}; +use xcm_executor::{traits::ConvertLocation, XcmExecutor}; +use xcm_simulator::mock_message_queue; + +pub type AccountId = AccountId32; +pub type Balance = u128; + +parameter_types! { + pub const BlockHashCount: u64 = 250; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Runtime { + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type AccountData = pallet_balances::AccountData; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; +} + + +pub const UNIT: Balance = 1; +parameter_types! { + pub const CollectionDeposit: Balance = 0 * UNIT; // 1 UNIT deposit to create asset collection + pub const ItemDeposit: Balance = 0 * UNIT; // 1/100 UNIT deposit to create asset item + pub const KeyLimit: u32 = 32; + pub const ValueLimit: u32 = 64; + pub const UniquesMetadataDepositBase: Balance = 0 * UNIT; + pub const AttributeDepositBase: Balance = 0 * UNIT; + pub const DepositPerByte: Balance = 0 * UNIT; + pub const UniquesStringLimit: u32 = 32; + pub const ApprovalsLimit: u32 = 1; + pub const ItemAttributesApprovalsLimit: u32 = 1; + pub const MaxTips: u32 = 1; + pub const MaxDeadlineDuration: u32 = 1; + pub const MaxAttributesPerCall: u32 = 10; + pub NftFeatures: pallet_nfts::PalletFeatures = pallet_nfts::PalletFeatures::all_enabled(); + pub const proposal_time_in_blocks_parameter: u32 = 10; + pub const max_owners_parameter: u32 = 1000000; + pub const max_votes: u32 = 1000000; +} + +pub type AccountPublic = ::Signer; + +impl pallet_nfts::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type CollectionId = u32; + type ItemId = u32; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type CreateOrigin = EnsureSigned; + type CollectionDeposit = CollectionDeposit; + type Locker = (); + type ItemDeposit = ItemDeposit; + type MetadataDepositBase = UniquesMetadataDepositBase; + type AttributeDepositBase = AttributeDepositBase; + type DepositPerByte = DepositPerByte; + type StringLimit = UniquesStringLimit; + type KeyLimit = KeyLimit; + type ValueLimit = ValueLimit; + type ApprovalsLimit = ApprovalsLimit; + type ItemAttributesApprovalsLimit = ItemAttributesApprovalsLimit; + type MaxTips = MaxTips; + type MaxDeadlineDuration = MaxDeadlineDuration; + type MaxAttributesPerCall = MaxAttributesPerCall; + type Features = NftFeatures; + type OffchainSignature = MultiSignature; + type OffchainPublic = AccountPublic; + type WeightInfo = (); +} + +// `EnsureOriginWithArg` impl for `CreateOrigin` which allows only XCM origins +// which are locations containing the class location. +pub struct ForeignCreators; +impl EnsureOriginWithArg for ForeignCreators { + type Success = AccountId; + + fn try_origin( + o: RuntimeOrigin, + a: &Location, + ) -> core::result::Result { + let origin_location = pallet_xcm::EnsureXcm::::try_origin(o.clone())?; + if !a.starts_with(&origin_location) { + return Err(o); + } + xcm_config::location_converter::LocationConverter::convert_location(&origin_location) + .ok_or(o) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(a: &Location) -> Result { + Ok(pallet_xcm::Origin::Xcm(a.clone()).into()) + } +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0); + pub const ReservedDmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0); +} + +impl mock_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +pub type LocalOriginToLocation = + SignedToAccountId32; + +pub struct TrustedLockerCase(PhantomData); +impl> ContainsPair for TrustedLockerCase { + fn contains(origin: &Location, asset: &Asset) -> bool { + let (o, a) = T::get(); + a.matches(asset) && &o == origin + } +} + +parameter_types! { + pub RelayTokenForRelay: (Location, AssetFilter) = (Parent.into(), Wild(AllOf { id: AssetId(Parent.into()), fun: WildFungible })); +} + +pub type TrustedLockers = TrustedLockerCase; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = weigher::Weigher; + type UniversalLocation = constants::UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = TrustedLockers; + type SovereignAccountOf = location_converter::LocationConverter; + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; +} + +impl crate::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type XcmSender = XcmRouter; + type RuntimeCall = RuntimeCall; + type ProposalTimeInBlocks = proposal_time_in_blocks_parameter; + type MaxOwners = max_owners_parameter; +} + +type Block = frame_system::mocking::MockBlock; + +impl parachain_info::Config for Runtime {} + +construct_runtime!( + pub struct Runtime { + System: frame_system, + Balances: pallet_balances, + MsgQueue: mock_message_queue, + PolkadotXcm: pallet_xcm, + NFTs: pallet_nfts, + XcNFT: crate, + ParachainInfo: parachain_info, + } +); \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/asset_transactor.rs b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/asset_transactor.rs new file mode 100644 index 000000000000..4d1e5d1ea4d3 --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/asset_transactor.rs @@ -0,0 +1,25 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::tests::testpara::{ + constants::KsmLocation, location_converter::LocationConverter, AccountId, Balances +}; +use xcm_builder::{FungibleAdapter, IsConcrete +}; + +type LocalAssetTransactor = FungibleAdapter, LocationConverter, AccountId, ()>; + +pub type AssetTransactor = LocalAssetTransactor; \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/barrier.rs b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/barrier.rs new file mode 100644 index 000000000000..5f1e655be05e --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/barrier.rs @@ -0,0 +1,20 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use frame_support::traits::Everything; +use xcm_builder::AllowUnpaidExecutionFrom; + +pub type Barrier = AllowUnpaidExecutionFrom; \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/constants.rs b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/constants.rs new file mode 100644 index 000000000000..59e1f077d87c --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/constants.rs @@ -0,0 +1,31 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::tests::testpara::Runtime; +use frame_support::parameter_types; +use xcm::latest::prelude::*; +use xcm_simulator::mock_message_queue::ParachainId; + +parameter_types! { + pub KsmPerSecondPerByte: (AssetId, u128, u128) = (AssetId(Parent.into()), 1, 1); + pub const MaxAssetsIntoHolding: u32 = 64; +} + +parameter_types! { + pub const KsmLocation: Location = Location::parent(); + pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainId::::get().into())].into(); +} \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/location_converter.rs b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/location_converter.rs new file mode 100644 index 000000000000..235bf3bfd6de --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/location_converter.rs @@ -0,0 +1,25 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::tests::testpara::{constants::RelayNetwork, AccountId}; +use xcm_builder::{AccountId32Aliases, DescribeAllTerminal, DescribeFamily, HashedDescription}; + +type LocationToAccountId = ( + HashedDescription>, + AccountId32Aliases, +); + +pub type LocationConverter = LocationToAccountId; \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/mod.rs b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/mod.rs new file mode 100644 index 000000000000..f7d340d7f54f --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/mod.rs @@ -0,0 +1,64 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +pub mod asset_transactor; +pub mod barrier; +pub mod constants; +pub mod location_converter; +pub mod origin_converter; +pub mod reserve; +pub mod teleporter; +pub mod weigher; + +use crate::tests::testpara::{MsgQueue, PolkadotXcm, RuntimeCall}; +use frame_support::traits::{Everything, Nothing}; +use xcm_builder::{EnsureDecodableXcm, FixedRateOfFungible, FrameTransactionalProcessor}; + +// Generated from `decl_test_network!` +pub type XcmRouter = EnsureDecodableXcm>; + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = asset_transactor::AssetTransactor; + type OriginConverter = origin_converter::OriginConverter; + type IsReserve = reserve::TrustedReserves; + type IsTeleporter = teleporter::TrustedTeleporters; + type UniversalLocation = constants::UniversalLocation; + type Barrier = barrier::Barrier; + type Weigher = weigher::Weigher; + type Trader = FixedRateOfFungible; + type ResponseHandler = (); + type AssetTrap = (); + type AssetLocker = PolkadotXcm; + type AssetExchanger = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = (); + type FeeManager = (); + type MaxAssetsIntoHolding = constants::MaxAssetsIntoHolding; + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Everything; + type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; +} \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/origin_converter.rs b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/origin_converter.rs new file mode 100644 index 000000000000..aa3a32ee5abe --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/origin_converter.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::tests::testpara::{ + constants::RelayNetwork, location_converter::LocationConverter, RuntimeOrigin, +}; +use pallet_xcm::XcmPassthrough; +use xcm_builder::{SignedAccountId32AsNative, SovereignSignedViaLocation}; + +type XcmOriginToCallOrigin = ( + SovereignSignedViaLocation, + SignedAccountId32AsNative, + XcmPassthrough, +); + +pub type OriginConverter = XcmOriginToCallOrigin; \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/reserve.rs b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/reserve.rs new file mode 100644 index 000000000000..f0700b59bb3a --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/reserve.rs @@ -0,0 +1,21 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::tests::testpara::teleporter::TrustedTeleporters; +use frame_support::traits::EverythingBut; +use xcm_builder::NativeAsset; + +pub type TrustedReserves = (NativeAsset, EverythingBut); \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/teleporter.rs b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/teleporter.rs new file mode 100644 index 000000000000..a068087953cd --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/teleporter.rs @@ -0,0 +1,27 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use frame_support::parameter_types; +use xcm::latest::prelude::*; + +parameter_types! { + pub NftCollectionOne: AssetFilter + = Wild(AllOf { fun: WildNonFungible, id: AssetId((Parent, GeneralIndex(1)).into()) }); + pub NftCollectionOneForRelay: (AssetFilter, Location) + = (NftCollectionOne::get(), (Parent,).into()); +} + +pub type TrustedTeleporters = xcm_builder::Case; \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/weigher.rs b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/weigher.rs new file mode 100644 index 000000000000..74ad2278aa14 --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testpara/xcm_config/weigher.rs @@ -0,0 +1,27 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::tests::testpara::RuntimeCall; +use frame_support::parameter_types; +use xcm::latest::prelude::*; +use xcm_builder::FixedWeightBounds; + +parameter_types! { + pub const UnitWeightCost: Weight = Weight::from_parts(1, 1); + pub const MaxInstructions: u32 = 100; +} + +pub type Weigher = FixedWeightBounds; \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testrelay.rs b/templates/parachain/pallets/xcnft/src/tests/testrelay.rs new file mode 100644 index 000000000000..c38dec1adc69 --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testrelay.rs @@ -0,0 +1,208 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Relay chain runtime mock. + +mod xcm_config; +pub use xcm_config::*; + +use frame_support::{ + construct_runtime, derive_impl, parameter_types, + traits::{ + AsEnsureOriginWithArg, ConstU128, Everything, Nothing, ProcessMessage, ProcessMessageError, + }, + weights::{Weight, WeightMeter}, +}; + +use frame_system::{EnsureRoot,EnsureSigned}; +use sp_core::ConstU32; +use sp_runtime::{traits::{Verify,IdentityLookup}, AccountId32,MultiSignature}; +use polkadot_runtime_parachains::{ + configuration, + inclusion::{AggregateMessageOrigin, UmpQueueId}, + origin, shared, +}; +use xcm::latest::prelude::*; +use xcm_builder::{IsConcrete, SignedToAccountId32}; +use xcm_executor::XcmExecutor; + +pub type AccountId = AccountId32; +pub type Balance = u128; + +parameter_types! { + pub const BlockHashCount: u64 = 250; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Runtime { + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type AccountData = pallet_balances::AccountData; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; +} + +pub const UNIT: Balance = 1; +parameter_types! { + pub const CollectionDeposit: Balance = 0 * UNIT; // 1 UNIT deposit to create asset collection + pub const ItemDeposit: Balance = 0 * UNIT; // 1/100 UNIT deposit to create asset item + pub const KeyLimit: u32 = 32; + pub const ValueLimit: u32 = 64; + pub const UniquesMetadataDepositBase: Balance = 0 * UNIT; + pub const AttributeDepositBase: Balance = 0 * UNIT; + pub const DepositPerByte: Balance = 0 * UNIT; + pub const UniquesStringLimit: u32 = 32; + pub const ApprovalsLimit: u32 = 1; + pub const ItemAttributesApprovalsLimit: u32 = 1; + pub const MaxTips: u32 = 1; + pub const MaxDeadlineDuration: u32 = 1; + pub const MaxAttributesPerCall: u32 = 10; + pub NftFeatures: pallet_nfts::PalletFeatures = pallet_nfts::PalletFeatures::all_enabled(); + pub const proposal_time_in_blocks_parameter: u32 = 10; + pub const max_owners_parameter: u32 = 1000000; + pub const max_votes: u32 = 1000000; +} + +pub type AccountPublic = ::Signer; + +impl pallet_nfts::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type CollectionId = u32; + type ItemId = u32; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type CreateOrigin = EnsureSigned; + type CollectionDeposit = CollectionDeposit; + type Locker = (); + type ItemDeposit = ItemDeposit; + type MetadataDepositBase = UniquesMetadataDepositBase; + type AttributeDepositBase = AttributeDepositBase; + type DepositPerByte = DepositPerByte; + type StringLimit = UniquesStringLimit; + type KeyLimit = KeyLimit; + type ValueLimit = ValueLimit; + type ApprovalsLimit = ApprovalsLimit; + type ItemAttributesApprovalsLimit = ItemAttributesApprovalsLimit; + type MaxTips = MaxTips; + type MaxDeadlineDuration = MaxDeadlineDuration; + type MaxAttributesPerCall = MaxAttributesPerCall; + type Features = NftFeatures; + type OffchainSignature = MultiSignature; + type OffchainPublic = AccountPublic; + type WeightInfo = (); +} + +impl shared::Config for Runtime { + type DisabledValidators = (); +} + +impl configuration::Config for Runtime { + type WeightInfo = configuration::TestWeightInfo; +} + +pub type LocalOriginToLocation = + SignedToAccountId32; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // Anyone can execute XCM messages locally... + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = weigher::Weigher; + type UniversalLocation = constants::UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type TrustedLockers = (); + type SovereignAccountOf = location_converter::LocationConverter; + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; +} + +impl origin::Config for Runtime {} + +type Block = frame_system::mocking::MockBlock; + +parameter_types! { + /// Amount of weight that can be spent per block to service messages. + pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000); + pub const MessageQueueHeapSize: u32 = 65_536; + pub const MessageQueueMaxStale: u32 = 16; +} + +/// Message processor to handle any messages that were enqueued into the `MessageQueue` pallet. +pub struct MessageProcessor; +impl ProcessMessage for MessageProcessor { + type Origin = AggregateMessageOrigin; + + fn process_message( + message: &[u8], + origin: Self::Origin, + meter: &mut WeightMeter, + id: &mut [u8; 32], + ) -> Result { + let para = match origin { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para, + }; + xcm_builder::ProcessXcmMessage::< + Junction, + xcm_executor::XcmExecutor, + RuntimeCall, + >::process_message(message, Junction::Parachain(para.into()), meter, id) + } +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = (); + type MessageProcessor = MessageProcessor; + type QueueChangeHandler = (); + type QueuePausedQuery = (); + type WeightInfo = (); +} + +construct_runtime!( + pub enum Runtime + { + System: frame_system, + Balances: pallet_balances, + ParasOrigin: origin, + XcmPallet: pallet_xcm, + NFTs: pallet_nfts, + MessageQueue: pallet_message_queue, + } +); \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/asset_transactor.rs b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/asset_transactor.rs new file mode 100644 index 000000000000..9b316306a5b3 --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/asset_transactor.rs @@ -0,0 +1,28 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::tests::testrelay::{ + constants::TokenLocation, location_converter::LocationConverter, AccountId, Balances, +}; +use xcm_builder::{ + AsPrefixedGeneralIndex, ConvertedConcreteId, FungibleAdapter, IsConcrete, NoChecking, + NonFungiblesAdapter, +}; +use xcm_executor::traits::JustTry; + +type LocalAssetTransactor = FungibleAdapter, LocationConverter, AccountId, ()>; + +pub type AssetTransactor = LocalAssetTransactor; \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/barrier.rs b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/barrier.rs new file mode 100644 index 000000000000..5f1e655be05e --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/barrier.rs @@ -0,0 +1,20 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use frame_support::traits::Everything; +use xcm_builder::AllowUnpaidExecutionFrom; + +pub type Barrier = AllowUnpaidExecutionFrom; \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/constants.rs b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/constants.rs new file mode 100644 index 000000000000..2266c223f40d --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/constants.rs @@ -0,0 +1,31 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use frame_support::parameter_types; +use xcm::latest::prelude::*; + +parameter_types! { + pub TokensPerSecondPerByte: (AssetId, u128, u128) = + (AssetId(TokenLocation::get()), 1_000_000_000_000, 1024 * 1024); + pub const MaxAssetsIntoHolding: u32 = 64; +} + +parameter_types! { + pub const TokenLocation: Location = Here.into_location(); + pub RelayNetwork: NetworkId = ByGenesis([0; 32]); + pub UniversalLocation: InteriorLocation = RelayNetwork::get().into(); + pub UnitWeightCost: u64 = 1_000; +} \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/location_converter.rs b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/location_converter.rs new file mode 100644 index 000000000000..88c26f6f7947 --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/location_converter.rs @@ -0,0 +1,25 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::tests::testrelay::{constants::RelayNetwork, AccountId}; +use xcm_builder::{AccountId32Aliases, DescribeAllTerminal, DescribeFamily, HashedDescription}; + +type LocationToAccountId = ( + HashedDescription>, + AccountId32Aliases, +); + +pub type LocationConverter = LocationToAccountId; \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/mod.rs b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/mod.rs new file mode 100644 index 000000000000..7a787e0f64be --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/mod.rs @@ -0,0 +1,64 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +pub mod asset_transactor; +pub mod barrier; +pub mod constants; +pub mod location_converter; +pub mod origin_converter; +pub mod teleporter; +pub mod weigher; + +use crate::tests::testrelay::{RuntimeCall, XcmPallet}; +use frame_support::traits::{Everything, Nothing}; +use xcm_builder::{EnsureDecodableXcm, FixedRateOfFungible, FrameTransactionalProcessor}; +use xcm_executor::Config; + +// Generated from `decl_test_network!` +pub type XcmRouter = EnsureDecodableXcm; + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = asset_transactor::AssetTransactor; + type OriginConverter = origin_converter::OriginConverter; + type IsReserve = (); + type IsTeleporter = teleporter::TrustedTeleporters; + type UniversalLocation = constants::UniversalLocation; + type Barrier = barrier::Barrier; + type Weigher = weigher::Weigher; + type Trader = FixedRateOfFungible; + type ResponseHandler = (); + type AssetTrap = (); + type AssetLocker = XcmPallet; + type AssetExchanger = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = (); + type FeeManager = (); + type MaxAssetsIntoHolding = constants::MaxAssetsIntoHolding; + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = XcmPallet; +} \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/origin_converter.rs b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/origin_converter.rs new file mode 100644 index 000000000000..ea14cbfd38e2 --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/origin_converter.rs @@ -0,0 +1,34 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::tests::testrelay::{ + constants::RelayNetwork, location_converter::LocationConverter, RuntimeOrigin, +}; +use polkadot_parachain_primitives::primitives::Id as ParaId; +use polkadot_runtime_parachains::origin; +use xcm_builder::{ + ChildParachainAsNative, ChildSystemParachainAsSuperuser, SignedAccountId32AsNative, + SovereignSignedViaLocation, +}; + +type LocalOriginConverter = ( + SovereignSignedViaLocation, + ChildParachainAsNative, + SignedAccountId32AsNative, + ChildSystemParachainAsSuperuser, +); + +pub type OriginConverter = LocalOriginConverter; \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/teleporter.rs b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/teleporter.rs new file mode 100644 index 000000000000..0d322538c592 --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/teleporter.rs @@ -0,0 +1,26 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use frame_support::parameter_types; +use xcm::latest::prelude::*; + +parameter_types! { + pub NftCollectionOnRelay: AssetFilter + = Wild(AllOf { fun: WildNonFungible, id: AssetId(GeneralIndex(1).into()) }); + pub NftCollectionForChild: (AssetFilter, Location) + = (NftCollectionOnRelay::get(), Parachain(1).into()); +} +pub type TrustedTeleporters = xcm_builder::Case; \ No newline at end of file diff --git a/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/weigher.rs b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/weigher.rs new file mode 100644 index 000000000000..b99051539394 --- /dev/null +++ b/templates/parachain/pallets/xcnft/src/tests/testrelay/xcm_config/weigher.rs @@ -0,0 +1,27 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use crate::tests::testrelay::RuntimeCall; +use frame_support::parameter_types; +use xcm::latest::prelude::*; +use xcm_builder::FixedWeightBounds; + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); + pub const MaxInstructions: u32 = 100; +} + +pub type Weigher = FixedWeightBounds; \ No newline at end of file