--- a/Cargo.lock +++ b/Cargo.lock @@ -5190,7 +5190,10 @@ "frame-try-runtime", "hex-literal", "log", + "orml-tokens", + "orml-traits", "orml-vesting", + "orml-xtokens", "pallet-aura", "pallet-balances", "pallet-base-fee", @@ -5202,6 +5205,7 @@ "pallet-evm-contract-helpers", "pallet-evm-migration", "pallet-evm-transaction-payment", + "pallet-foreing-assets", "pallet-fungible", "pallet-inflation", "pallet-nonfungible", @@ -5307,6 +5311,53 @@ ] [[package]] +name = "orml-tokens" +version = "0.4.1-dev" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?branch=polkadot-v0.9.27#377213f750755cc48e80a3131eaae63b5eda8362" +dependencies = [ + "frame-support", + "frame-system", + "orml-traits", + "parity-scale-codec 3.1.5", + "scale-info", + "serde", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "orml-traits" +version = "0.4.1-dev" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?branch=polkadot-v0.9.27#377213f750755cc48e80a3131eaae63b5eda8362" +dependencies = [ + "frame-support", + "impl-trait-for-tuples", + "num-traits", + "orml-utilities", + "parity-scale-codec 3.1.5", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "xcm", +] + +[[package]] +name = "orml-utilities" +version = "0.4.1-dev" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?branch=polkadot-v0.9.27#377213f750755cc48e80a3131eaae63b5eda8362" +dependencies = [ + "frame-support", + "parity-scale-codec 3.1.5", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] name = "orml-vesting" version = "0.4.1-dev" source = "git+https://github.com/open-web3-stack/open-runtime-module-library?branch=polkadot-v0.9.27#377213f750755cc48e80a3131eaae63b5eda8362" @@ -5322,6 +5373,41 @@ ] [[package]] +name = "orml-xcm-support" +version = "0.4.1-dev" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?branch=polkadot-v0.9.27#377213f750755cc48e80a3131eaae63b5eda8362" +dependencies = [ + "frame-support", + "orml-traits", + "parity-scale-codec 3.1.5", + "sp-runtime", + "sp-std", + "xcm", + "xcm-executor", +] + +[[package]] +name = "orml-xtokens" +version = "0.4.1-dev" +source = "git+https://github.com/open-web3-stack/open-runtime-module-library?branch=polkadot-v0.9.27#377213f750755cc48e80a3131eaae63b5eda8362" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "orml-traits", + "orml-xcm-support", + "pallet-xcm", + "parity-scale-codec 3.1.5", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "xcm", + "xcm-executor", +] + +[[package]] name = "os_str_bytes" version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5789,6 +5875,33 @@ ] [[package]] +name = "pallet-foreing-assets" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "hex", + "log", + "orml-tokens", + "pallet-balances", + "pallet-common", + "pallet-fungible", + "pallet-timestamp", + "parity-scale-codec 3.1.5", + "scale-info", + "serde", + "serde_json", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "up-data-structs", + "xcm", + "xcm-builder", + "xcm-executor", +] + +[[package]] name = "pallet-fungible" version = "0.1.3" dependencies = [ @@ -12130,7 +12243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "digest 0.10.3", "rand 0.8.5", "static_assertions", @@ -12473,7 +12586,7 @@ [[package]] name = "up-common" -version = "0.9.25" +version = "0.9.27" dependencies = [ "fp-rpc", "frame-support", --- a/pallets/foreing-assets/Cargo.toml +++ b/pallets/foreing-assets/Cargo.toml @@ -9,26 +9,29 @@ serde = { version = "1.0.136", optional = true } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24", default-features = false } -sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24", default-features = false } -frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24", default-features = false } -frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27", default-features = false } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27", default-features = false } up-data-structs = { default-features = false, path = '../../primitives/data-structs' } -pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24", default-features = false } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27", default-features = false } pallet-common = { default-features = false, path = '../common' } pallet-fungible = { default-features = false, path = '../fungible' } -xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.24", default-features = false } -xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.24", default-features = false } -xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.24", default-features = false } -orml-tokens = { git = 'https://github.com/UniqueNetwork/open-runtime-module-library', branch = 'unique-polkadot-v0.9.24', version = "0.4.1-dev", default-features = false } +xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.27", default-features = false } +xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.27", default-features = false } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.27", default-features = false } +#orml-tokens = { git = 'https://github.com/UniqueNetwork/open-runtime-module-library', branch = 'unique-polkadot-v0.9.24', version = "0.4.1-dev", default-features = false } +orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v0.9.27", version = "0.4.1-dev", default-features = false } +#git = "https://github.com/open-web3-stack/open-runtime-module-library" +#branch = "polkadot-v0.9.27" [dev-dependencies] serde_json = "1.0.68" hex = { version = "0.4" } -sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" } -sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" } -pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" } -pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" } +pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" } [features] default = ["std"] --- a/pallets/fungible/src/lib.rs +++ b/pallets/fungible/src/lib.rs @@ -167,8 +167,14 @@ Value = u128, QueryKind = ValueQuery, >; + + /// Foreign collection flag + #[pallet::storage] + pub type ForeignCollection = + StorageMap; } + /// Wrapper around untyped collection handle, asserting inner collection is of fungible type. /// Required for interaction with Fungible collections, type safety and implementation [`solidity_interface`][`evm_coder::solidity_interface`]. pub struct FungibleHandle(pallet_common::CollectionHandle); @@ -215,6 +221,16 @@ >::init_collection(owner, data, false) } + /// Initializes the collection with ForeignCollection flag. Returns [CollectionId] on success, [DispatchError] otherwise. + pub fn init_foreign_collection( + owner: T::CrossAccountId, + data: CreateCollectionData, + ) -> Result { + let id = >::init_collection(owner, data, false)?; + >::insert(id, true); + Ok(id) + } + /// Destroys a collection. pub fn destroy_collection( collection: FungibleHandle, @@ -230,6 +246,7 @@ PalletCommon::destroy_collection(collection.0, sender)?; + >::remove(id); >::remove(id); let _ = >::clear_prefix((id,), u32::MAX, None); let _ = >::clear_prefix((id,), u32::MAX, None); @@ -257,6 +274,12 @@ .checked_sub(amount) .ok_or(>::TokenValueTooLow)?; + // Foreign collection check + ensure!( + !>::get(collection.id), + >::NoPermission + ); + if collection.permissions.access() == AccessMode::AllowList { collection.check_allowlist(owner)?; } @@ -288,6 +311,46 @@ Ok(()) } + /// Burns the specified amount of the token. + pub fn burn_foreign( + collection: &FungibleHandle, + owner: &T::CrossAccountId, + amount: u128, + ) -> DispatchResult { + let total_supply = >::get(collection.id) + .checked_sub(amount) + .ok_or(>::TokenValueTooLow)?; + + let balance = >::get((collection.id, owner)) + .checked_sub(amount) + .ok_or(>::TokenValueTooLow)?; + // ========= + + if balance == 0 { + >::remove((collection.id, owner)); + >::unnest_if_nested(owner, collection.id, TokenId::default()); + } else { + >::insert((collection.id, owner), balance); + } + >::insert(collection.id, total_supply); + + >::deposit_log( + ERC20Events::Transfer { + from: *owner.as_eth(), + to: H160::default(), + value: amount.into(), + } + .to_log(collection_id_to_address(collection.id)), + ); + >::deposit_event(CommonEvent::ItemDestroyed( + collection.id, + TokenId::default(), + owner.clone(), + amount, + )); + Ok(()) + } + /// Transfers the specified amount of tokens. Will check that /// the transfer is allowed for the token. /// @@ -373,6 +436,12 @@ data: BTreeMap, nesting_budget: &dyn Budget, ) -> DispatchResult { + // Foreign collection check + ensure!( + !>::get(collection.id), + >::NoPermission + ); + if !collection.is_owner_or_admin(sender) { ensure!( collection.permissions.mint_mode(), @@ -442,6 +511,68 @@ Ok(()) } + /// Minting tokens for multiple IDs. + /// See [`create_item_foreign`][`Pallet::create_item_foreign`] for more details. + pub fn create_multiple_items_foreign( + collection: &FungibleHandle, + sender: &T::CrossAccountId, + data: BTreeMap, + nesting_budget: &dyn Budget, + ) -> DispatchResult { + let total_supply = data + .iter() + .map(|(_, v)| *v) + .try_fold(>::get(collection.id), |acc, v| { + acc.checked_add(v) + }) + .ok_or(ArithmeticError::Overflow)?; + + let mut balances = data; + for (k, v) in balances.iter_mut() { + *v = >::get((collection.id, &k)) + .checked_add(*v) + .ok_or(ArithmeticError::Overflow)?; + } + + for (to, _) in balances.iter() { + >::check_nesting( + sender.clone(), + to, + collection.id, + TokenId::default(), + nesting_budget, + )?; + } + + // ========= + + >::insert(collection.id, total_supply); + for (user, amount) in balances { + >::insert((collection.id, &user), amount); + >::nest_if_sent_to_token_unchecked( + &user, + collection.id, + TokenId::default(), + ); + >::deposit_log( + ERC20Events::Transfer { + from: H160::default(), + to: *user.as_eth(), + value: amount.into(), + } + .to_log(collection_id_to_address(collection.id)), + ); + >::deposit_event(CommonEvent::ItemCreated( + collection.id, + TokenId::default(), + user.clone(), + amount, + )); + } + + Ok(()) + } + fn set_allowance_unchecked( collection: &FungibleHandle, owner: &T::CrossAccountId, @@ -615,6 +746,24 @@ ) } + /// Creates fungible token. + /// + /// - `data`: Contains user who will become the owners of the tokens and amount + /// of tokens he will receive. + pub fn create_item_foreign( + collection: &FungibleHandle, + sender: &T::CrossAccountId, + data: CreateItemData, + nesting_budget: &dyn Budget, + ) -> DispatchResult { + Self::create_multiple_items_foreign( + collection, + sender, + [(data.0, data.1)].into_iter().collect(), + nesting_budget, + ) + } + /// Returns 10 tokens owners in no particular order /// /// There is no direct way to get token holders in ascending order, --- /dev/null +++ b/runtime/common/config/pallets/foreign_asset.rs @@ -0,0 +1,9 @@ +use crate::{Runtime, Event, Balances}; +use up_common::types::AccountId; + +impl pallet_foreing_assets::Config for Runtime { + type Event = Event; + type Currency = Balances; + type RegisterOrigin = frame_system::EnsureRoot; + type WeightInfo = (); +} --- a/runtime/common/config/pallets/mod.rs +++ b/runtime/common/config/pallets/mod.rs @@ -40,6 +40,9 @@ #[cfg(feature = "scheduler")] pub mod scheduler; +#[cfg(feature = "foreign-asset")] +pub mod foreign_asset; + parameter_types! { pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating(); pub const CollectionCreationPrice: Balance = 2 * UNIQUE; --- a/runtime/common/construct_runtime/mod.rs +++ b/runtime/common/construct_runtime/mod.rs @@ -42,6 +42,8 @@ Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event} = 34, Sudo: pallet_sudo::{Pallet, Call, Storage, Config, Event} = 35, Vesting: orml_vesting::{Pallet, Storage, Call, Event, Config} = 37, + XTokens: orml_xtokens = 38, + Tokens: orml_tokens = 39, // Vesting: pallet_vesting::{Pallet, Call, Config, Storage, Event} = 37, // Contracts: pallet_contracts::{Pallet, Call, Storage, Event} = 38, --- a/runtime/opal/Cargo.toml +++ b/runtime/opal/Cargo.toml @@ -120,13 +120,18 @@ 'up-sponsorship/std', "orml-vesting/std", + "orml-tokens/std", + "orml-xtokens/std", + "orml-traits/std", + "pallet-foreing-assets/std" ] limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing'] -opal-runtime = ['refungible', 'scheduler', 'rmrk'] +opal-runtime = ['refungible', 'scheduler', 'rmrk', 'foreign-asset'] refungible = [] scheduler = [] rmrk = [] +foreign-asset = [] ################################################################################ # Substrate Dependencies @@ -399,6 +404,24 @@ version = "0.4.1-dev" default-features = false +[dependencies.orml-xtokens] +git = "https://github.com/open-web3-stack/open-runtime-module-library" +branch = "polkadot-v0.9.27" +version = "0.4.1-dev" +default-features = false + +[dependencies.orml-tokens] +git = "https://github.com/open-web3-stack/open-runtime-module-library" +branch = "polkadot-v0.9.27" +version = "0.4.1-dev" +default-features = false + +[dependencies.orml-traits] +git = "https://github.com/open-web3-stack/open-runtime-module-library" +branch = "polkadot-v0.9.27" +version = "0.4.1-dev" +default-features = false + ################################################################################ # local dependencies @@ -437,6 +460,7 @@ fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.27" } evm-coder = { default-features = false, path = '../../crates/evm-coder' } up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.27' } +pallet-foreing-assets = { default-features = false, path = "../../pallets/foreing-assets" } ################################################################################ # Build Dependencies --- a/runtime/opal/src/lib.rs +++ b/runtime/opal/src/lib.rs @@ -35,6 +35,8 @@ #[path = "../../common/mod.rs"] mod runtime_common; +pub mod xcm_config; + pub use runtime_common::*; pub const RUNTIME_NAME: &str = "opal";