diff --git a/Cargo.lock b/Cargo.lock index 1983b157..469b0449 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7219,6 +7219,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-fungibles" +version = "0.1.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-assets", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", +] + [[package]] name = "pallet-grandpa" version = "29.0.0" @@ -9745,6 +9760,7 @@ dependencies = [ "pallet-balances", "pallet-collator-selection", "pallet-contracts", + "pallet-fungibles", "pallet-message-queue", "pallet-multisig", "pallet-nft-fractionalization", diff --git a/Cargo.toml b/Cargo.toml index 6b3cde02..31b5acda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ members = [ "runtime/devnet", "runtime/testnet", "integration-tests", + "pallets/*", "primitives", "scripts/fund-dev-accounts", ] diff --git a/pallets/fungibles/Cargo.toml b/pallets/fungibles/Cargo.toml new file mode 100644 index 00000000..7c3f44e4 --- /dev/null +++ b/pallets/fungibles/Cargo.toml @@ -0,0 +1,50 @@ +[package] +name = "pallet-fungibles" +authors = ["Anonymous"] +description = "Frame Pallet" +version = "0.1.0" +license = "Unlicense" +edition = "2021" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec.workspace = true +scale-info.workspace = true + +# Substrate +frame-benchmarking.workspace = true +frame-support.workspace = true +frame-system.workspace = true +pallet-assets.workspace = true +sp-runtime.workspace = true + +[dev-dependencies] +sp-core.workspace = true +sp-io.workspace = true + +[features] +default = ["std"] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +std = [ + "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "pallet-assets/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/pallets/fungibles/src/benchmarking.rs b/pallets/fungibles/src/benchmarking.rs new file mode 100644 index 00000000..f3b0b0ec --- /dev/null +++ b/pallets/fungibles/src/benchmarking.rs @@ -0,0 +1,22 @@ +//! Benchmarking setup for pallet-parachain-template + +// https://docs.substrate.io/test/benchmark/ + +use super::*; + +#[allow(unused)] +use crate::Pallet as Template; +use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_system::RawOrigin; + +benchmarks! { + do_something { + let s in 0 .. 100; + let caller: T::AccountId = whitelisted_caller(); + }: _(RawOrigin::Signed(caller), s) + verify { + assert_eq!(Something::::get(), Some(s)); + } +} + +impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test,); diff --git a/pallets/fungibles/src/lib.rs b/pallets/fungibles/src/lib.rs new file mode 100644 index 00000000..5833f02a --- /dev/null +++ b/pallets/fungibles/src/lib.rs @@ -0,0 +1,64 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::{pallet_prelude::*, traits::fungibles::Inspect}; + use frame_system::pallet_prelude::*; + use sp_runtime::traits::StaticLookup; + + type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; + type AssetIdOf = as Inspect< + ::AccountId, + >>::AssetId; + type AssetIdParameterOf = + >::AssetIdParameter; + type BalanceOf = as Inspect< + ::AccountId, + >>::Balance; + // Should be defined in primitives. + type TrustBackedAssetsInstance = pallet_assets::Instance1; + + #[pallet::config] + pub trait Config: + frame_system::Config + pallet_assets::Config + { + } + + #[pallet::pallet] + pub struct Pallet(_); + + use pallet_assets::WeightInfo; + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(>::WeightInfo::transfer_keep_alive())] + pub fn transfer( + origin: OriginFor, + id: AssetIdParameterOf, + target: AccountIdLookupOf, + amount: BalanceOf, + ) -> DispatchResult { + pallet_assets::Pallet::::transfer_keep_alive( + origin, id, target, amount, + ) + } + } + + impl Pallet { + pub fn total_supply(id: AssetIdOf) -> BalanceOf { + pallet_assets::Pallet::::total_supply(id) + } + } +} diff --git a/pallets/fungibles/src/mock.rs b/pallets/fungibles/src/mock.rs new file mode 100644 index 00000000..82412fe3 --- /dev/null +++ b/pallets/fungibles/src/mock.rs @@ -0,0 +1,60 @@ +use frame_support::{parameter_types, traits::Everything}; +use frame_system as system; +use sp_core::H256; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, +}; + +type Block = frame_system::mocking::MockBlock; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + fungibles: crate::{Pallet, Call, Storage, Event}, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl crate::Config for Test { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +// Build genesis storage according to the mock runtime. +pub fn new_test_ext() -> sp_io::TestExternalities { + system::GenesisConfig::::default().build_storage().unwrap().into() +} diff --git a/pallets/fungibles/src/tests.rs b/pallets/fungibles/src/tests.rs new file mode 100644 index 00000000..a5116a72 --- /dev/null +++ b/pallets/fungibles/src/tests.rs @@ -0,0 +1,22 @@ +use crate::{mock::*, Error}; +use frame_support::{assert_noop, assert_ok}; + +// https://docs.substrate.io/test/ + +#[test] +fn it_works_for_default_value() { + new_test_ext().execute_with(|| { + // Dispatch a signed extrinsic. + assert_ok!(fungibles::do_something(RuntimeOrigin::signed(1), 42)); + // Read pallet storage and assert an expected result. + assert_eq!(fungibles::something(), Some(42)); + }); +} + +#[test] +fn correct_error_for_none_value() { + new_test_ext().execute_with(|| { + // Ensure the expected error is thrown when no value is present. + assert_noop!(fungibles::cause_error(RuntimeOrigin::signed(1)), Error::::NoneValue); + }); +} diff --git a/runtime/devnet/Cargo.toml b/runtime/devnet/Cargo.toml index 70e6e9c9..d2c03dbe 100644 --- a/runtime/devnet/Cargo.toml +++ b/runtime/devnet/Cargo.toml @@ -24,6 +24,7 @@ smallvec.workspace = true # Local pop-primitives = { workspace = true, features = ["assets", "cross-chain", "nfts"] } pop-runtime-common = { workspace = true, default-features = false } +pallet-fungibles = { path = "../../pallets/fungibles/", default-features = false } # Substrate frame-benchmarking.workspace = true @@ -119,6 +120,7 @@ std = [ "pallet-balances/std", "pallet-collator-selection/std", "pallet-contracts/std", + "pallet-fungibles/std", "pallet-message-queue/std", "pallet-multisig/std", "pallet-nft-fractionalization/std", diff --git a/runtime/devnet/src/config/assets.rs b/runtime/devnet/src/config/assets.rs index 2c8ea952..dd7cb6c9 100644 --- a/runtime/devnet/src/config/assets.rs +++ b/runtime/devnet/src/config/assets.rs @@ -119,3 +119,5 @@ impl pallet_assets::Config for Runtime { #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); } + +impl pallet_fungibles::Config for Runtime {} diff --git a/runtime/devnet/src/extensions/mod.rs b/runtime/devnet/src/extensions/mod.rs index d2bd63e7..e6f0e287 100644 --- a/runtime/devnet/src/extensions/mod.rs +++ b/runtime/devnet/src/extensions/mod.rs @@ -174,7 +174,7 @@ fn construct_call( match pallet_index { index if index == super::Assets::index() as u8 => { let call = versioned_construct_assets_call(version, call_index, params)?; - Ok(RuntimeCall::Assets(call)) + Ok(RuntimeCall::Fungibles(call)) }, _ => Err(DispatchError::Other("UnknownFunctionId")), } @@ -199,7 +199,8 @@ fn versioned_construct_assets_call( version: u8, call_index: u8, params: Vec, -) -> Result, DispatchError> { + // ) -> Result, DispatchError> { +) -> Result, DispatchError> { match version { V0 => v0::assets::construct_assets_call(call_index, params), _ => Err(DispatchError::Other("UnknownFunctionId")), diff --git a/runtime/devnet/src/extensions/v0/assets.rs b/runtime/devnet/src/extensions/v0/assets.rs index c6b15b4e..3411368f 100644 --- a/runtime/devnet/src/extensions/v0/assets.rs +++ b/runtime/devnet/src/extensions/v0/assets.rs @@ -49,27 +49,33 @@ pub(crate) fn construct_assets_key( pub(crate) fn construct_assets_call( call_index: u8, params: Vec, -) -> Result, DispatchError> { + // ) -> Result, DispatchError> { +) -> Result, DispatchError> { match call_index { 9 => { let (id, target, amount) = <(AssetId, AccountId32, Balance)>::decode(&mut ¶ms[..]) .map_err(|_| DispatchError::Other("DecodingFailed"))?; - Ok(pallet_assets::Call::::transfer_keep_alive { + // Ok(pallet_assets::Call::::transfer_keep_alive { + // id: Compact(id), + // target: MultiAddress::Id(target), + // amount, + // }) + Ok(pallet_fungibles::Call::::transfer { id: Compact(id), target: MultiAddress::Id(target), amount, }) }, - 22 => { - let (id, delegate, amount) = - <(AssetId, AccountId32, Balance)>::decode(&mut ¶ms[..]) - .map_err(|_| DispatchError::Other("DecodingFailed"))?; - Ok(pallet_assets::Call::::approve_transfer { - id: Compact(id), - delegate: MultiAddress::Id(delegate), - amount, - }) - }, + // 22 => { + // let (id, delegate, amount) = + // <(AssetId, AccountId32, Balance)>::decode(&mut ¶ms[..]) + // .map_err(|_| DispatchError::Other("DecodingFailed"))?; + // Ok(pallet_assets::Call::::approve_transfer { + // id: Compact(id), + // delegate: MultiAddress::Id(delegate), + // amount, + // }) + // }, // other calls _ => Err(DispatchError::Other("UnknownFunctionId")), } diff --git a/runtime/devnet/src/lib.rs b/runtime/devnet/src/lib.rs index 9ab64043..822fc24d 100644 --- a/runtime/devnet/src/lib.rs +++ b/runtime/devnet/src/lib.rs @@ -252,7 +252,7 @@ impl Contains for FilteredCalls { /// A type to identify allowed calls to the Runtime from contracts. Used by Pop API pub struct AllowedApiCalls; -impl Contains for crate::AllowedApiCalls { +impl Contains for AllowedApiCalls { fn contains(c: &RuntimeCall) -> bool { use config::assets::AssetsCall; use pallet_nfts::Call as NftsCall; @@ -321,7 +321,7 @@ impl Contains for crate::AllowedApiCalls { | NftsCall::create_swap { .. } | NftsCall::cancel_swap { .. } | NftsCall::claim_swap { .. } - ) + ) | RuntimeCall::Fungibles(pallet_fungibles::Call::transfer { .. }) ) } } @@ -663,6 +663,7 @@ construct_runtime!( Nfts: pallet_nfts = 50, NftFractionalization: pallet_nft_fractionalization = 51, Assets: pallet_assets:: = 52, + Fungibles: pallet_fungibles = 53, } );