difftreelog
feature: make collection creation methods `payable`
in: master
19 files changed
crates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/solidity_interface.rs
+++ b/crates/evm-coder/procedural/src/solidity_interface.rs
@@ -560,6 +560,7 @@
selector: u32,
args: Vec<MethodArg>,
has_normal_args: bool,
+ has_value_args: bool,
mutability: Mutability,
result: Type,
weight: Option<Expr>,
@@ -647,14 +648,20 @@
.unwrap_or_else(|| cases::camelcase::to_camel_case(&ident.to_string()));
let mut selector_str = camel_name.clone();
selector_str.push('(');
- let mut has_normal_args = false;
- for (i, arg) in args.iter().filter(|arg| !arg.is_special()).enumerate() {
- if i != 0 {
- selector_str.push(',');
+ let mut normal_args_count = 0u32;
+ let mut has_value_args = false;
+ for arg in args.iter() {
+ if arg.is_value() {
+ has_value_args = true;
+ } else if !arg.is_special() {
+ if normal_args_count != 0 {
+ selector_str.push(',');
+ }
+ write!(selector_str, "{}", arg.selector_ty()).unwrap();
+ normal_args_count = normal_args_count.saturating_add(1);
}
- write!(selector_str, "{}", arg.selector_ty()).unwrap();
- has_normal_args = true;
}
+ let has_normal_args = normal_args_count > 0;
selector_str.push(')');
let selector = fn_selector_str(&selector_str);
@@ -667,6 +674,7 @@
selector,
args,
has_normal_args,
+ has_value_args,
mutability,
result: result.clone(),
weight,
@@ -823,7 +831,7 @@
let docs = &self.docs;
let selector_str = &self.selector_str;
let selector = self.selector;
-
+ let is_payable = self.has_value_args;
quote! {
SolidityFunction {
docs: &[#(#docs),*],
@@ -831,6 +839,7 @@
selector: #selector,
name: #camel_name,
mutability: #mutability,
+ is_payable: #is_payable,
args: (
#(
#args,
crates/evm-coder/src/solidity.rsdiffbeforeafterboth--- a/crates/evm-coder/src/solidity.rs
+++ b/crates/evm-coder/src/solidity.rs
@@ -422,6 +422,7 @@
pub args: A,
pub result: R,
pub mutability: SolidityMutability,
+ pub is_payable: bool,
}
impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {
fn solidity_name(
@@ -452,6 +453,9 @@
SolidityMutability::View => write!(writer, " view")?,
SolidityMutability::Mutable => {}
}
+ if self.is_payable {
+ write!(writer, " payable")?;
+ }
if !self.result.is_empty() {
write!(writer, " returns (")?;
self.result.solidity_name(writer, tc)?;
pallets/common/src/dispatch.rsdiffbeforeafterboth--- a/pallets/common/src/dispatch.rs
+++ b/pallets/common/src/dispatch.rs
@@ -78,6 +78,7 @@
/// * `data` - Description of the created collection.
fn create(
sender: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError>;
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -866,6 +866,7 @@
/// * `flags` - Extra flags to store.
pub fn init_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
flags: CollectionFlags,
) -> Result<CollectionId, DispatchError> {
@@ -939,7 +940,7 @@
),
);
<T as Config>::Currency::settle(
- owner.as_sub(),
+ payer.as_sub(),
imbalance,
WithdrawReasons::TRANSFER,
ExistenceRequirement::KeepAlive,
pallets/foreign-assets/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Foreign assets18//!19//! - [`Config`]20//! - [`Call`]21//! - [`Pallet`]22//!23//! ## Overview24//!25//! The foreign assests pallet provides functions for:26//!27//! - Local and foreign assets management. The foreign assets can be updated without runtime upgrade.28//! - Bounds between asset and target collection for cross chain transfer and inner transfers.29//!30//! ## Overview31//!32//! Under construction3334#![cfg_attr(not(feature = "std"), no_std)]35#![allow(clippy::unused_unit)]3637use frame_support::{38 dispatch::DispatchResult,39 ensure,40 pallet_prelude::*,41 traits::{fungible, fungibles, Currency, EnsureOrigin},42 RuntimeDebug,43};44use frame_system::pallet_prelude::*;45use up_data_structs::{CollectionMode};46use pallet_fungible::{Pallet as PalletFungible};47use scale_info::{TypeInfo};48use sp_runtime::{49 traits::{One, Zero},50 ArithmeticError,51};52use sp_std::{boxed::Box, vec::Vec};53use up_data_structs::{CollectionId, TokenId, CreateCollectionData};5455// NOTE:v1::MultiLocation is used in storages, we would need to do migration if upgrade the56// MultiLocation in the future.57use xcm::opaque::latest::prelude::XcmError;58use xcm::{v1::MultiLocation, VersionedMultiLocation};59use xcm_executor::{traits::WeightTrader, Assets};6061use pallet_common::erc::CrossAccountId;6263#[cfg(feature = "std")]64use serde::{Deserialize, Serialize};6566// TODO: Move to primitives67// Id of native currency.68// 0 - QTZ\UNQ69// 1 - KSM\DOT70#[derive(71 Clone,72 Copy,73 Eq,74 PartialEq,75 PartialOrd,76 Ord,77 MaxEncodedLen,78 RuntimeDebug,79 Encode,80 Decode,81 TypeInfo,82)]83#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]84pub enum NativeCurrency {85 Here = 0,86 Parent = 1,87}8889#[derive(90 Clone,91 Copy,92 Eq,93 PartialEq,94 PartialOrd,95 Ord,96 MaxEncodedLen,97 RuntimeDebug,98 Encode,99 Decode,100 TypeInfo,101)]102#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]103pub enum AssetIds {104 ForeignAssetId(ForeignAssetId),105 NativeAssetId(NativeCurrency),106}107108pub trait TryAsForeign<T, F> {109 fn try_as_foreign(asset: T) -> Option<F>;110}111112impl TryAsForeign<AssetIds, ForeignAssetId> for AssetIds {113 fn try_as_foreign(asset: AssetIds) -> Option<ForeignAssetId> {114 match asset {115 AssetIds::ForeignAssetId(id) => Some(id),116 _ => None,117 }118 }119}120121pub type ForeignAssetId = u32;122pub type CurrencyId = AssetIds;123124mod impl_fungibles;125pub mod weights;126127#[cfg(feature = "runtime-benchmarks")]128mod benchmarking;129130pub use module::*;131pub use weights::WeightInfo;132133/// Type alias for currency balance.134pub type BalanceOf<T> =135 <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;136137/// A mapping between ForeignAssetId and AssetMetadata.138pub trait AssetIdMapping<ForeignAssetId, MultiLocation, AssetMetadata> {139 /// Returns the AssetMetadata associated with a given ForeignAssetId.140 fn get_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option<AssetMetadata>;141 /// Returns the MultiLocation associated with a given ForeignAssetId.142 fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option<MultiLocation>;143 /// Returns the CurrencyId associated with a given MultiLocation.144 fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId>;145}146147pub struct XcmForeignAssetIdMapping<T>(sp_std::marker::PhantomData<T>);148149impl<T: Config> AssetIdMapping<ForeignAssetId, MultiLocation, AssetMetadata<BalanceOf<T>>>150 for XcmForeignAssetIdMapping<T>151{152 fn get_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option<AssetMetadata<BalanceOf<T>>> {153 log::trace!(target: "fassets::asset_metadatas", "call");154 Pallet::<T>::asset_metadatas(AssetIds::ForeignAssetId(foreign_asset_id))155 }156157 fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option<MultiLocation> {158 log::trace!(target: "fassets::get_multi_location", "call");159 Pallet::<T>::foreign_asset_locations(foreign_asset_id)160 }161162 fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId> {163 log::trace!(target: "fassets::get_currency_id", "call");164 Some(AssetIds::ForeignAssetId(165 Pallet::<T>::location_to_currency_ids(multi_location).unwrap_or(0),166 ))167 }168}169170#[frame_support::pallet]171pub mod module {172 use super::*;173174 #[pallet::config]175 pub trait Config:176 frame_system::Config177 + pallet_common::Config178 + pallet_fungible::Config179 + orml_tokens::Config180 + pallet_balances::Config181 {182 /// The overarching event type.183 type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;184185 /// Currency type for withdraw and balance storage.186 type Currency: Currency<Self::AccountId>;187188 /// Required origin for registering asset.189 type RegisterOrigin: EnsureOrigin<Self::Origin>;190191 /// Weight information for the extrinsics in this module.192 type WeightInfo: WeightInfo;193 }194195 #[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)]196 pub struct AssetMetadata<Balance> {197 pub name: Vec<u8>,198 pub symbol: Vec<u8>,199 pub decimals: u8,200 pub minimal_balance: Balance,201 }202203 #[pallet::error]204 pub enum Error<T> {205 /// The given location could not be used (e.g. because it cannot be expressed in the206 /// desired version of XCM).207 BadLocation,208 /// MultiLocation existed209 MultiLocationExisted,210 /// AssetId not exists211 AssetIdNotExists,212 /// AssetId exists213 AssetIdExisted,214 }215216 #[pallet::event]217 #[pallet::generate_deposit(fn deposit_event)]218 pub enum Event<T: Config> {219 /// The foreign asset registered.220 ForeignAssetRegistered {221 asset_id: ForeignAssetId,222 asset_address: MultiLocation,223 metadata: AssetMetadata<BalanceOf<T>>,224 },225 /// The foreign asset updated.226 ForeignAssetUpdated {227 asset_id: ForeignAssetId,228 asset_address: MultiLocation,229 metadata: AssetMetadata<BalanceOf<T>>,230 },231 /// The asset registered.232 AssetRegistered {233 asset_id: AssetIds,234 metadata: AssetMetadata<BalanceOf<T>>,235 },236 /// The asset updated.237 AssetUpdated {238 asset_id: AssetIds,239 metadata: AssetMetadata<BalanceOf<T>>,240 },241 }242243 /// Next available Foreign AssetId ID.244 ///245 /// NextForeignAssetId: ForeignAssetId246 #[pallet::storage]247 #[pallet::getter(fn next_foreign_asset_id)]248 pub type NextForeignAssetId<T: Config> = StorageValue<_, ForeignAssetId, ValueQuery>;249 /// The storages for MultiLocations.250 ///251 /// ForeignAssetLocations: map ForeignAssetId => Option<MultiLocation>252 #[pallet::storage]253 #[pallet::getter(fn foreign_asset_locations)]254 pub type ForeignAssetLocations<T: Config> =255 StorageMap<_, Twox64Concat, ForeignAssetId, MultiLocation, OptionQuery>;256257 /// The storages for CurrencyIds.258 ///259 /// LocationToCurrencyIds: map MultiLocation => Option<ForeignAssetId>260 #[pallet::storage]261 #[pallet::getter(fn location_to_currency_ids)]262 pub type LocationToCurrencyIds<T: Config> =263 StorageMap<_, Twox64Concat, MultiLocation, ForeignAssetId, OptionQuery>;264265 /// The storages for AssetMetadatas.266 ///267 /// AssetMetadatas: map AssetIds => Option<AssetMetadata>268 #[pallet::storage]269 #[pallet::getter(fn asset_metadatas)]270 pub type AssetMetadatas<T: Config> =271 StorageMap<_, Twox64Concat, AssetIds, AssetMetadata<BalanceOf<T>>, OptionQuery>;272273 /// The storages for assets to fungible collection binding274 ///275 #[pallet::storage]276 #[pallet::getter(fn asset_binding)]277 pub type AssetBinding<T: Config> =278 StorageMap<_, Twox64Concat, ForeignAssetId, CollectionId, OptionQuery>;279280 #[pallet::pallet]281 #[pallet::without_storage_info]282 pub struct Pallet<T>(_);283284 #[pallet::call]285 impl<T: Config> Pallet<T> {286 #[pallet::weight(<T as Config>::WeightInfo::register_foreign_asset())]287 pub fn register_foreign_asset(288 origin: OriginFor<T>,289 owner: T::AccountId,290 location: Box<VersionedMultiLocation>,291 metadata: Box<AssetMetadata<BalanceOf<T>>>,292 ) -> DispatchResult {293 T::RegisterOrigin::ensure_origin(origin.clone())?;294295 let location: MultiLocation = (*location)296 .try_into()297 .map_err(|()| Error::<T>::BadLocation)?;298299 let md = metadata.clone();300 let name: Vec<u16> = md.name.into_iter().map(|x| x as u16).collect::<Vec<u16>>();301 let mut description: Vec<u16> = "Foreign assets collection for "302 .encode_utf16()303 .collect::<Vec<u16>>();304 description.append(&mut name.clone());305306 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {307 name: name.try_into().unwrap(),308 description: description.try_into().unwrap(),309 mode: CollectionMode::Fungible(md.decimals),310 ..Default::default()311 };312313 let bounded_collection_id = <PalletFungible<T>>::init_foreign_collection(314 CrossAccountId::from_sub(owner),315 data,316 )?;317 let foreign_asset_id =318 Self::do_register_foreign_asset(&location, &metadata, bounded_collection_id)?;319320 Self::deposit_event(Event::<T>::ForeignAssetRegistered {321 asset_id: foreign_asset_id,322 asset_address: location,323 metadata: *metadata,324 });325 Ok(())326 }327328 #[pallet::weight(<T as Config>::WeightInfo::update_foreign_asset())]329 pub fn update_foreign_asset(330 origin: OriginFor<T>,331 foreign_asset_id: ForeignAssetId,332 location: Box<VersionedMultiLocation>,333 metadata: Box<AssetMetadata<BalanceOf<T>>>,334 ) -> DispatchResult {335 T::RegisterOrigin::ensure_origin(origin)?;336337 let location: MultiLocation = (*location)338 .try_into()339 .map_err(|()| Error::<T>::BadLocation)?;340 Self::do_update_foreign_asset(foreign_asset_id, &location, &metadata)?;341342 Self::deposit_event(Event::<T>::ForeignAssetUpdated {343 asset_id: foreign_asset_id,344 asset_address: location,345 metadata: *metadata,346 });347 Ok(())348 }349 }350}351352impl<T: Config> Pallet<T> {353 fn get_next_foreign_asset_id() -> Result<ForeignAssetId, DispatchError> {354 NextForeignAssetId::<T>::try_mutate(|current| -> Result<ForeignAssetId, DispatchError> {355 let id = *current;356 *current = current357 .checked_add(One::one())358 .ok_or(ArithmeticError::Overflow)?;359 Ok(id)360 })361 }362363 fn do_register_foreign_asset(364 location: &MultiLocation,365 metadata: &AssetMetadata<BalanceOf<T>>,366 bounded_collection_id: CollectionId,367 ) -> Result<ForeignAssetId, DispatchError> {368 let foreign_asset_id = Self::get_next_foreign_asset_id()?;369 LocationToCurrencyIds::<T>::try_mutate(location, |maybe_currency_ids| -> DispatchResult {370 ensure!(371 maybe_currency_ids.is_none(),372 Error::<T>::MultiLocationExisted373 );374 *maybe_currency_ids = Some(foreign_asset_id);375 // *maybe_currency_ids = Some(CurrencyId::ForeignAsset(foreign_asset_id));376377 ForeignAssetLocations::<T>::try_mutate(378 foreign_asset_id,379 |maybe_location| -> DispatchResult {380 ensure!(maybe_location.is_none(), Error::<T>::MultiLocationExisted);381 *maybe_location = Some(location.clone());382383 AssetMetadatas::<T>::try_mutate(384 AssetIds::ForeignAssetId(foreign_asset_id),385 |maybe_asset_metadatas| -> DispatchResult {386 ensure!(maybe_asset_metadatas.is_none(), Error::<T>::AssetIdExisted);387 *maybe_asset_metadatas = Some(metadata.clone());388 Ok(())389 },390 )391 },392 )?;393394 AssetBinding::<T>::try_mutate(foreign_asset_id, |collection_id| -> DispatchResult {395 *collection_id = Some(bounded_collection_id);396 Ok(())397 })398 })?;399400 Ok(foreign_asset_id)401 }402403 fn do_update_foreign_asset(404 foreign_asset_id: ForeignAssetId,405 location: &MultiLocation,406 metadata: &AssetMetadata<BalanceOf<T>>,407 ) -> DispatchResult {408 ForeignAssetLocations::<T>::try_mutate(409 foreign_asset_id,410 |maybe_multi_locations| -> DispatchResult {411 let old_multi_locations = maybe_multi_locations412 .as_mut()413 .ok_or(Error::<T>::AssetIdNotExists)?;414415 AssetMetadatas::<T>::try_mutate(416 AssetIds::ForeignAssetId(foreign_asset_id),417 |maybe_asset_metadatas| -> DispatchResult {418 ensure!(419 maybe_asset_metadatas.is_some(),420 Error::<T>::AssetIdNotExists421 );422423 // modify location424 if location != old_multi_locations {425 LocationToCurrencyIds::<T>::remove(old_multi_locations.clone());426 LocationToCurrencyIds::<T>::try_mutate(427 location,428 |maybe_currency_ids| -> DispatchResult {429 ensure!(430 maybe_currency_ids.is_none(),431 Error::<T>::MultiLocationExisted432 );433 // *maybe_currency_ids = Some(CurrencyId::ForeignAsset(foreign_asset_id));434 *maybe_currency_ids = Some(foreign_asset_id);435 Ok(())436 },437 )?;438 }439 *maybe_asset_metadatas = Some(metadata.clone());440 *old_multi_locations = location.clone();441 Ok(())442 },443 )444 },445 )446 }447}448449pub use frame_support::{450 traits::{451 fungibles::{Balanced, CreditOf},452 tokens::currency::Currency as CurrencyT,453 OnUnbalanced as OnUnbalancedT,454 },455 weights::{WeightToFeePolynomial, WeightToFee},456};457458pub struct FreeForAll<459 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,460 AssetId: Get<MultiLocation>,461 AccountId,462 Currency: CurrencyT<AccountId>,463 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,464>(465 Weight,466 Currency::Balance,467 PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,468);469470impl<471 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,472 AssetId: Get<MultiLocation>,473 AccountId,474 Currency: CurrencyT<AccountId>,475 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,476 > WeightTrader for FreeForAll<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>477{478 fn new() -> Self {479 Self(0, Zero::zero(), PhantomData)480 }481482 fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {483 log::trace!(target: "fassets::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment);484 Ok(payment)485 }486}487impl<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> Drop488 for FreeForAll<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>489where490 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,491 AssetId: Get<MultiLocation>,492 Currency: CurrencyT<AccountId>,493 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,494{495 fn drop(&mut self) {496 OnUnbalanced::on_unbalanced(Currency::issue(self.1));497 }498}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Foreign assets18//!19//! - [`Config`]20//! - [`Call`]21//! - [`Pallet`]22//!23//! ## Overview24//!25//! The foreign assests pallet provides functions for:26//!27//! - Local and foreign assets management. The foreign assets can be updated without runtime upgrade.28//! - Bounds between asset and target collection for cross chain transfer and inner transfers.29//!30//! ## Overview31//!32//! Under construction3334#![cfg_attr(not(feature = "std"), no_std)]35#![allow(clippy::unused_unit)]3637use frame_support::{38 dispatch::DispatchResult,39 ensure,40 pallet_prelude::*,41 traits::{fungible, fungibles, Currency, EnsureOrigin},42 RuntimeDebug,43};44use frame_system::pallet_prelude::*;45use up_data_structs::{CollectionMode};46use pallet_fungible::{Pallet as PalletFungible};47use scale_info::{TypeInfo};48use sp_runtime::{49 traits::{One, Zero},50 ArithmeticError,51};52use sp_std::{boxed::Box, vec::Vec};53use up_data_structs::{CollectionId, TokenId, CreateCollectionData};5455// NOTE:v1::MultiLocation is used in storages, we would need to do migration if upgrade the56// MultiLocation in the future.57use xcm::opaque::latest::prelude::XcmError;58use xcm::{v1::MultiLocation, VersionedMultiLocation};59use xcm_executor::{traits::WeightTrader, Assets};6061use pallet_common::erc::CrossAccountId;6263#[cfg(feature = "std")]64use serde::{Deserialize, Serialize};6566// TODO: Move to primitives67// Id of native currency.68// 0 - QTZ\UNQ69// 1 - KSM\DOT70#[derive(71 Clone,72 Copy,73 Eq,74 PartialEq,75 PartialOrd,76 Ord,77 MaxEncodedLen,78 RuntimeDebug,79 Encode,80 Decode,81 TypeInfo,82)]83#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]84pub enum NativeCurrency {85 Here = 0,86 Parent = 1,87}8889#[derive(90 Clone,91 Copy,92 Eq,93 PartialEq,94 PartialOrd,95 Ord,96 MaxEncodedLen,97 RuntimeDebug,98 Encode,99 Decode,100 TypeInfo,101)]102#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]103pub enum AssetIds {104 ForeignAssetId(ForeignAssetId),105 NativeAssetId(NativeCurrency),106}107108pub trait TryAsForeign<T, F> {109 fn try_as_foreign(asset: T) -> Option<F>;110}111112impl TryAsForeign<AssetIds, ForeignAssetId> for AssetIds {113 fn try_as_foreign(asset: AssetIds) -> Option<ForeignAssetId> {114 match asset {115 AssetIds::ForeignAssetId(id) => Some(id),116 _ => None,117 }118 }119}120121pub type ForeignAssetId = u32;122pub type CurrencyId = AssetIds;123124mod impl_fungibles;125pub mod weights;126127#[cfg(feature = "runtime-benchmarks")]128mod benchmarking;129130pub use module::*;131pub use weights::WeightInfo;132133/// Type alias for currency balance.134pub type BalanceOf<T> =135 <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;136137/// A mapping between ForeignAssetId and AssetMetadata.138pub trait AssetIdMapping<ForeignAssetId, MultiLocation, AssetMetadata> {139 /// Returns the AssetMetadata associated with a given ForeignAssetId.140 fn get_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option<AssetMetadata>;141 /// Returns the MultiLocation associated with a given ForeignAssetId.142 fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option<MultiLocation>;143 /// Returns the CurrencyId associated with a given MultiLocation.144 fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId>;145}146147pub struct XcmForeignAssetIdMapping<T>(sp_std::marker::PhantomData<T>);148149impl<T: Config> AssetIdMapping<ForeignAssetId, MultiLocation, AssetMetadata<BalanceOf<T>>>150 for XcmForeignAssetIdMapping<T>151{152 fn get_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option<AssetMetadata<BalanceOf<T>>> {153 log::trace!(target: "fassets::asset_metadatas", "call");154 Pallet::<T>::asset_metadatas(AssetIds::ForeignAssetId(foreign_asset_id))155 }156157 fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option<MultiLocation> {158 log::trace!(target: "fassets::get_multi_location", "call");159 Pallet::<T>::foreign_asset_locations(foreign_asset_id)160 }161162 fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId> {163 log::trace!(target: "fassets::get_currency_id", "call");164 Some(AssetIds::ForeignAssetId(165 Pallet::<T>::location_to_currency_ids(multi_location).unwrap_or(0),166 ))167 }168}169170#[frame_support::pallet]171pub mod module {172 use super::*;173174 #[pallet::config]175 pub trait Config:176 frame_system::Config177 + pallet_common::Config178 + pallet_fungible::Config179 + orml_tokens::Config180 + pallet_balances::Config181 {182 /// The overarching event type.183 type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;184185 /// Currency type for withdraw and balance storage.186 type Currency: Currency<Self::AccountId>;187188 /// Required origin for registering asset.189 type RegisterOrigin: EnsureOrigin<Self::Origin>;190191 /// Weight information for the extrinsics in this module.192 type WeightInfo: WeightInfo;193 }194195 #[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)]196 pub struct AssetMetadata<Balance> {197 pub name: Vec<u8>,198 pub symbol: Vec<u8>,199 pub decimals: u8,200 pub minimal_balance: Balance,201 }202203 #[pallet::error]204 pub enum Error<T> {205 /// The given location could not be used (e.g. because it cannot be expressed in the206 /// desired version of XCM).207 BadLocation,208 /// MultiLocation existed209 MultiLocationExisted,210 /// AssetId not exists211 AssetIdNotExists,212 /// AssetId exists213 AssetIdExisted,214 }215216 #[pallet::event]217 #[pallet::generate_deposit(fn deposit_event)]218 pub enum Event<T: Config> {219 /// The foreign asset registered.220 ForeignAssetRegistered {221 asset_id: ForeignAssetId,222 asset_address: MultiLocation,223 metadata: AssetMetadata<BalanceOf<T>>,224 },225 /// The foreign asset updated.226 ForeignAssetUpdated {227 asset_id: ForeignAssetId,228 asset_address: MultiLocation,229 metadata: AssetMetadata<BalanceOf<T>>,230 },231 /// The asset registered.232 AssetRegistered {233 asset_id: AssetIds,234 metadata: AssetMetadata<BalanceOf<T>>,235 },236 /// The asset updated.237 AssetUpdated {238 asset_id: AssetIds,239 metadata: AssetMetadata<BalanceOf<T>>,240 },241 }242243 /// Next available Foreign AssetId ID.244 ///245 /// NextForeignAssetId: ForeignAssetId246 #[pallet::storage]247 #[pallet::getter(fn next_foreign_asset_id)]248 pub type NextForeignAssetId<T: Config> = StorageValue<_, ForeignAssetId, ValueQuery>;249 /// The storages for MultiLocations.250 ///251 /// ForeignAssetLocations: map ForeignAssetId => Option<MultiLocation>252 #[pallet::storage]253 #[pallet::getter(fn foreign_asset_locations)]254 pub type ForeignAssetLocations<T: Config> =255 StorageMap<_, Twox64Concat, ForeignAssetId, MultiLocation, OptionQuery>;256257 /// The storages for CurrencyIds.258 ///259 /// LocationToCurrencyIds: map MultiLocation => Option<ForeignAssetId>260 #[pallet::storage]261 #[pallet::getter(fn location_to_currency_ids)]262 pub type LocationToCurrencyIds<T: Config> =263 StorageMap<_, Twox64Concat, MultiLocation, ForeignAssetId, OptionQuery>;264265 /// The storages for AssetMetadatas.266 ///267 /// AssetMetadatas: map AssetIds => Option<AssetMetadata>268 #[pallet::storage]269 #[pallet::getter(fn asset_metadatas)]270 pub type AssetMetadatas<T: Config> =271 StorageMap<_, Twox64Concat, AssetIds, AssetMetadata<BalanceOf<T>>, OptionQuery>;272273 /// The storages for assets to fungible collection binding274 ///275 #[pallet::storage]276 #[pallet::getter(fn asset_binding)]277 pub type AssetBinding<T: Config> =278 StorageMap<_, Twox64Concat, ForeignAssetId, CollectionId, OptionQuery>;279280 #[pallet::pallet]281 #[pallet::without_storage_info]282 pub struct Pallet<T>(_);283284 #[pallet::call]285 impl<T: Config> Pallet<T> {286 #[pallet::weight(<T as Config>::WeightInfo::register_foreign_asset())]287 pub fn register_foreign_asset(288 origin: OriginFor<T>,289 owner: T::AccountId,290 location: Box<VersionedMultiLocation>,291 metadata: Box<AssetMetadata<BalanceOf<T>>>,292 ) -> DispatchResult {293 T::RegisterOrigin::ensure_origin(origin.clone())?;294295 let location: MultiLocation = (*location)296 .try_into()297 .map_err(|()| Error::<T>::BadLocation)?;298299 let md = metadata.clone();300 let name: Vec<u16> = md.name.into_iter().map(|x| x as u16).collect::<Vec<u16>>();301 let mut description: Vec<u16> = "Foreign assets collection for "302 .encode_utf16()303 .collect::<Vec<u16>>();304 description.append(&mut name.clone());305306 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {307 name: name.try_into().unwrap(),308 description: description.try_into().unwrap(),309 mode: CollectionMode::Fungible(md.decimals),310 ..Default::default()311 };312 let owner = T::CrossAccountId::from_sub(owner);313 let bounded_collection_id = <PalletFungible<T>>::init_foreign_collection(314 owner.clone(),315 owner,316 data,317 )?;318 let foreign_asset_id =319 Self::do_register_foreign_asset(&location, &metadata, bounded_collection_id)?;320321 Self::deposit_event(Event::<T>::ForeignAssetRegistered {322 asset_id: foreign_asset_id,323 asset_address: location,324 metadata: *metadata,325 });326 Ok(())327 }328329 #[pallet::weight(<T as Config>::WeightInfo::update_foreign_asset())]330 pub fn update_foreign_asset(331 origin: OriginFor<T>,332 foreign_asset_id: ForeignAssetId,333 location: Box<VersionedMultiLocation>,334 metadata: Box<AssetMetadata<BalanceOf<T>>>,335 ) -> DispatchResult {336 T::RegisterOrigin::ensure_origin(origin)?;337338 let location: MultiLocation = (*location)339 .try_into()340 .map_err(|()| Error::<T>::BadLocation)?;341 Self::do_update_foreign_asset(foreign_asset_id, &location, &metadata)?;342343 Self::deposit_event(Event::<T>::ForeignAssetUpdated {344 asset_id: foreign_asset_id,345 asset_address: location,346 metadata: *metadata,347 });348 Ok(())349 }350 }351}352353impl<T: Config> Pallet<T> {354 fn get_next_foreign_asset_id() -> Result<ForeignAssetId, DispatchError> {355 NextForeignAssetId::<T>::try_mutate(|current| -> Result<ForeignAssetId, DispatchError> {356 let id = *current;357 *current = current358 .checked_add(One::one())359 .ok_or(ArithmeticError::Overflow)?;360 Ok(id)361 })362 }363364 fn do_register_foreign_asset(365 location: &MultiLocation,366 metadata: &AssetMetadata<BalanceOf<T>>,367 bounded_collection_id: CollectionId,368 ) -> Result<ForeignAssetId, DispatchError> {369 let foreign_asset_id = Self::get_next_foreign_asset_id()?;370 LocationToCurrencyIds::<T>::try_mutate(location, |maybe_currency_ids| -> DispatchResult {371 ensure!(372 maybe_currency_ids.is_none(),373 Error::<T>::MultiLocationExisted374 );375 *maybe_currency_ids = Some(foreign_asset_id);376 // *maybe_currency_ids = Some(CurrencyId::ForeignAsset(foreign_asset_id));377378 ForeignAssetLocations::<T>::try_mutate(379 foreign_asset_id,380 |maybe_location| -> DispatchResult {381 ensure!(maybe_location.is_none(), Error::<T>::MultiLocationExisted);382 *maybe_location = Some(location.clone());383384 AssetMetadatas::<T>::try_mutate(385 AssetIds::ForeignAssetId(foreign_asset_id),386 |maybe_asset_metadatas| -> DispatchResult {387 ensure!(maybe_asset_metadatas.is_none(), Error::<T>::AssetIdExisted);388 *maybe_asset_metadatas = Some(metadata.clone());389 Ok(())390 },391 )392 },393 )?;394395 AssetBinding::<T>::try_mutate(foreign_asset_id, |collection_id| -> DispatchResult {396 *collection_id = Some(bounded_collection_id);397 Ok(())398 })399 })?;400401 Ok(foreign_asset_id)402 }403404 fn do_update_foreign_asset(405 foreign_asset_id: ForeignAssetId,406 location: &MultiLocation,407 metadata: &AssetMetadata<BalanceOf<T>>,408 ) -> DispatchResult {409 ForeignAssetLocations::<T>::try_mutate(410 foreign_asset_id,411 |maybe_multi_locations| -> DispatchResult {412 let old_multi_locations = maybe_multi_locations413 .as_mut()414 .ok_or(Error::<T>::AssetIdNotExists)?;415416 AssetMetadatas::<T>::try_mutate(417 AssetIds::ForeignAssetId(foreign_asset_id),418 |maybe_asset_metadatas| -> DispatchResult {419 ensure!(420 maybe_asset_metadatas.is_some(),421 Error::<T>::AssetIdNotExists422 );423424 // modify location425 if location != old_multi_locations {426 LocationToCurrencyIds::<T>::remove(old_multi_locations.clone());427 LocationToCurrencyIds::<T>::try_mutate(428 location,429 |maybe_currency_ids| -> DispatchResult {430 ensure!(431 maybe_currency_ids.is_none(),432 Error::<T>::MultiLocationExisted433 );434 // *maybe_currency_ids = Some(CurrencyId::ForeignAsset(foreign_asset_id));435 *maybe_currency_ids = Some(foreign_asset_id);436 Ok(())437 },438 )?;439 }440 *maybe_asset_metadatas = Some(metadata.clone());441 *old_multi_locations = location.clone();442 Ok(())443 },444 )445 },446 )447 }448}449450pub use frame_support::{451 traits::{452 fungibles::{Balanced, CreditOf},453 tokens::currency::Currency as CurrencyT,454 OnUnbalanced as OnUnbalancedT,455 },456 weights::{WeightToFeePolynomial, WeightToFee},457};458459pub struct FreeForAll<460 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,461 AssetId: Get<MultiLocation>,462 AccountId,463 Currency: CurrencyT<AccountId>,464 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,465>(466 Weight,467 Currency::Balance,468 PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,469);470471impl<472 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,473 AssetId: Get<MultiLocation>,474 AccountId,475 Currency: CurrencyT<AccountId>,476 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,477 > WeightTrader for FreeForAll<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>478{479 fn new() -> Self {480 Self(0, Zero::zero(), PhantomData)481 }482483 fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {484 log::trace!(target: "fassets::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment);485 Ok(payment)486 }487}488impl<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> Drop489 for FreeForAll<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>490where491 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,492 AssetId: Get<MultiLocation>,493 Currency: CurrencyT<AccountId>,494 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,495{496 fn drop(&mut self) {497 OnUnbalanced::on_unbalanced(Currency::issue(self.1));498 }499}pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -210,18 +210,21 @@
/// Initializes the collection. Returns [CollectionId] on success, [DispatchError] otherwise.
pub fn init_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError> {
- <PalletCommon<T>>::init_collection(owner, data, CollectionFlags::default())
+ <PalletCommon<T>>::init_collection(owner, payer, data, CollectionFlags::default())
}
/// Initializes the collection with ForeignCollection flag. Returns [CollectionId] on success, [DispatchError] otherwise.
pub fn init_foreign_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError> {
let id = <PalletCommon<T>>::init_collection(
owner,
+ payer,
data,
CollectionFlags {
foreign: true,
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -405,11 +405,13 @@
/// - `data`: Contains settings for collection limits and permissions.
pub fn init_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
is_external: bool,
) -> Result<CollectionId, DispatchError> {
<PalletCommon<T>>::init_collection(
owner,
+ payer,
data,
CollectionFlags {
external: is_external,
pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -1448,7 +1448,7 @@
data: CreateCollectionData<T::AccountId>,
properties: impl Iterator<Item = Property>,
) -> Result<CollectionId, DispatchError> {
- let collection_id = <PalletNft<T>>::init_collection(sender, data, true);
+ let collection_id = <PalletNft<T>>::init_collection(sender.clone(), sender, data, true);
if let Err(DispatchError::Arithmetic(_)) = &collection_id {
return Err(<Error<T>>::NoAvailableCollectionId.into());
pallets/proxy-rmrk-equip/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-equip/src/lib.rs
+++ b/pallets/proxy-rmrk-equip/src/lib.rs
@@ -251,7 +251,7 @@
};
let collection_id_res =
- <PalletNft<T>>::init_collection(cross_sender.clone(), data, true);
+ <PalletNft<T>>::init_collection(cross_sender.clone(), cross_sender.clone(), data, true);
if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {
return Err(<Error<T>>::NoAvailableBaseId.into());
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -373,9 +373,10 @@
/// - `data`: Contains settings for collection limits and permissions.
pub fn init_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError> {
- <PalletCommon<T>>::init_collection(owner, data, CollectionFlags::default())
+ <PalletCommon<T>>::init_collection(owner, payer, data, CollectionFlags::default())
}
/// Destroy RFT collection
pallets/unique/src/eth/mod.rsdiffbeforeafterboth--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -28,7 +28,7 @@
static_property::{key, value as property_value},
},
};
-use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
+use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder};
use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};
use up_data_structs::{
CollectionName, CollectionDescription, CollectionTokenPrefix, CreateCollectionData,
@@ -156,6 +156,7 @@
T: Config + pallet_nonfungible::Config + pallet_refungible::Config,
>(
caller: caller,
+ value: value,
name: string,
description: string,
token_prefix: string,
@@ -172,8 +173,16 @@
base_uri_value,
add_properties,
)?;
+ let value = value.as_u128();
+ let creation_price: Result<u128> = T::CollectionCreationPrice::get()
+ .try_into()
+ .map_err(|_| "collection creation price should be convertible to u128".into());
+ if value != creation_price? {
+ return Err("Sent amount not equals to collection creation price".into());
+ }
+ let collection_helpers_address = T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());
- let collection_id = T::CollectionDispatch::create(caller.clone(), data)
+ let collection_id = T::CollectionDispatch::create(caller.clone(), collection_helpers_address, data)
.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
let address = pallet_common::eth::collection_id_to_address(collection_id);
Ok(address)
@@ -183,7 +192,7 @@
#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]
impl<T> EvmCollectionHelpers<T>
where
- T: Config + pallet_nonfungible::Config + pallet_refungible::Config,
+ T: Config + pallet_common::Config + pallet_nonfungible::Config + pallet_refungible::Config,
{
/// Create an NFT collection
/// @param name Name of the collection
@@ -209,8 +218,17 @@
Default::default(),
false,
)?;
- let collection_id = T::CollectionDispatch::create(caller, data)
- .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
+ let value = value.as_u128();
+ let creation_price: Result<u128> = T::CollectionCreationPrice::get()
+ .try_into()
+ .map_err(|_| "collection creation price should be convertible to u128".into());
+ let creation_price = creation_price?;
+ if value != creation_price {
+ return Err(format!("Sent amount not equals to collection creation price ({0})", creation_price).into());
+ }
+ let collection_helpers_address = T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());
+ let collection_id =
+ T::CollectionDispatch::create(caller, collection_helpers_address, data).map_err(dispatch_to_evm::<T>)?;
let address = pallet_common::eth::collection_id_to_address(collection_id);
Ok(address)
@@ -221,6 +239,7 @@
fn create_nonfungible_collection_with_properties(
&mut self,
caller: caller,
+ value: value,
name: string,
description: string,
token_prefix: string,
@@ -236,7 +255,15 @@
base_uri_value,
true,
)?;
- let collection_id = T::CollectionDispatch::create(caller, data)
+ let value = value.as_u128();
+ let creation_price: Result<u128> = T::CollectionCreationPrice::get()
+ .try_into()
+ .map_err(|_| "collection creation price should be convertible to u128".into());
+ if value != creation_price? {
+ return Err("Sent amount not equals to collection creation price".into());
+ }
+ let collection_helpers_address = T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());
+ let collection_id = T::CollectionDispatch::create(caller, collection_helpers_address, data)
.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
let address = pallet_common::eth::collection_id_to_address(collection_id);
@@ -248,12 +275,14 @@
fn create_refungible_collection(
&mut self,
caller: caller,
+ value: value,
name: string,
description: string,
token_prefix: string,
) -> Result<address> {
create_refungible_collection_internal::<T>(
caller,
+ value,
name,
description,
token_prefix,
@@ -267,6 +296,7 @@
fn create_refungible_collection_with_properties(
&mut self,
caller: caller,
+ value: value,
name: string,
description: string,
token_prefix: string,
@@ -274,6 +304,7 @@
) -> Result<address> {
create_refungible_collection_internal::<T>(
caller,
+ value,
name,
description,
token_prefix,
pallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/unique/src/eth/stubs/CollectionHelpers.soldiffbeforeafterboth--- a/pallets/unique/src/eth/stubs/CollectionHelpers.sol
+++ b/pallets/unique/src/eth/stubs/CollectionHelpers.sol
@@ -36,7 +36,7 @@
string memory name,
string memory description,
string memory tokenPrefix
- ) public returns (address) {
+ ) public payable returns (address) {
require(false, stub_error);
name;
description;
@@ -52,7 +52,7 @@
string memory description,
string memory tokenPrefix,
string memory baseUri
- ) public returns (address) {
+ ) public payable returns (address) {
require(false, stub_error);
name;
description;
@@ -68,7 +68,7 @@
string memory name,
string memory description,
string memory tokenPrefix
- ) public returns (address) {
+ ) public payable returns (address) {
require(false, stub_error);
name;
description;
@@ -84,7 +84,7 @@
string memory description,
string memory tokenPrefix,
string memory baseUri
- ) public returns (address) {
+ ) public payable returns (address) {
require(false, stub_error);
name;
description;
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -344,8 +344,8 @@
let sender = ensure_signed(origin)?;
// =========
-
- let _id = T::CollectionDispatch::create(T::CrossAccountId::from_sub(sender), data)?;
+ let sender = T::CrossAccountId::from_sub(sender);
+ let _id = T::CollectionDispatch::create(sender.clone(), sender, data)?;
Ok(())
}
runtime/common/dispatch.rsdiffbeforeafterboth--- a/runtime/common/dispatch.rs
+++ b/runtime/common/dispatch.rs
@@ -55,21 +55,22 @@
{
fn create(
sender: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError> {
let id = match data.mode {
- CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data, false)?,
+ CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, payer, data, false)?,
CollectionMode::Fungible(decimal_points) => {
// check params
ensure!(
decimal_points <= MAX_DECIMAL_POINTS,
pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded
);
- <PalletFungible<T>>::init_collection(sender, data)?
+ <PalletFungible<T>>::init_collection(sender, payer, data)?
}
#[cfg(feature = "refungible")]
- CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,
+ CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, payer, data)?,
#[cfg(not(feature = "refungible"))]
CollectionMode::ReFungible => return unsupported!(T),
tests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth--- a/tests/src/eth/api/CollectionHelpers.sol
+++ b/tests/src/eth/api/CollectionHelpers.sol
@@ -31,7 +31,7 @@
string memory name,
string memory description,
string memory tokenPrefix
- ) external returns (address);
+ ) external payable returns (address);
/// @dev EVM selector for this function is: 0xa634a5f9,
/// or in textual repr: createERC721MetadataCompatibleCollection(string,string,string,string)
@@ -40,7 +40,7 @@
string memory description,
string memory tokenPrefix,
string memory baseUri
- ) external returns (address);
+ ) external payable returns (address);
/// @dev EVM selector for this function is: 0xab173450,
/// or in textual repr: createRFTCollection(string,string,string)
@@ -48,7 +48,7 @@
string memory name,
string memory description,
string memory tokenPrefix
- ) external returns (address);
+ ) external payable returns (address);
/// @dev EVM selector for this function is: 0xa5596388,
/// or in textual repr: createERC721MetadataCompatibleRFTCollection(string,string,string,string)
@@ -57,7 +57,7 @@
string memory description,
string memory tokenPrefix,
string memory baseUri
- ) external returns (address);
+ ) external payable returns (address);
/// Check if a collection exists
/// @param collectionAddress Address of the collection in question
tests/src/eth/collectionHelpersAbi.jsondiffbeforeafterboth--- a/tests/src/eth/collectionHelpersAbi.json
+++ b/tests/src/eth/collectionHelpersAbi.json
@@ -27,7 +27,7 @@
],
"name": "createERC721MetadataCompatibleCollection",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "nonpayable",
+ "stateMutability": "payable",
"type": "function"
},
{
@@ -39,7 +39,7 @@
],
"name": "createERC721MetadataCompatibleRFTCollection",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "nonpayable",
+ "stateMutability": "payable",
"type": "function"
},
{
@@ -50,7 +50,7 @@
],
"name": "createNonfungibleCollection",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "nonpayable",
+ "stateMutability": "payable",
"type": "function"
},
{
@@ -61,7 +61,7 @@
],
"name": "createRFTCollection",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "nonpayable",
+ "stateMutability": "payable",
"type": "function"
},
{
tests/src/eth/fractionalizer/Fractionalizer.soldiffbeforeafterboth--- a/tests/src/eth/fractionalizer/Fractionalizer.sol
+++ b/tests/src/eth/fractionalizer/Fractionalizer.sol
@@ -18,7 +18,8 @@
mapping(address => bool) nftCollectionAllowList;
mapping(address => mapping(uint256 => uint256)) public nft2rftMapping;
mapping(address => Token) public rft2nftMapping;
- bytes32 refungibleCollectionType = keccak256(bytes("ReFungible"));
+ //use constant to reduce gas cost
+ bytes32 constant refungibleCollectionType = keccak256(bytes("ReFungible"));
receive() external payable onlyOwner {}
@@ -51,11 +52,12 @@
/// Throws if `msg.sender` is not owner or admin of provided RFT collection.
/// Can only be called by contract owner.
/// @param _collection address of RFT collection.
- function setRFTCollection(address _collection) public onlyOwner {
+ function setRFTCollection(address _collection) external onlyOwner {
require(rftCollection == address(0), "RFT collection is already set");
UniqueRefungible refungibleContract = UniqueRefungible(_collection);
string memory collectionType = refungibleContract.uniqueCollectionType();
+ // compare hashed to reduce gas cost
require(
keccak256(bytes(collectionType)) == refungibleCollectionType,
"Wrong collection type. Collection is not refungible."
@@ -79,7 +81,7 @@
string calldata _name,
string calldata _description,
string calldata _tokenPrefix
- ) public onlyOwner {
+ ) external onlyOwner {
require(rftCollection == address(0), "RFT collection is already set");
address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;
rftCollection = CollectionHelpers(collectionHelpers).createRFTCollection(_name, _description, _tokenPrefix);
@@ -90,7 +92,7 @@
/// @dev Can only be called by contract owner.
/// @param collection NFT token address.
/// @param status `true` to allow and `false` to disallow NFT token.
- function setNftCollectionIsAllowed(address collection, bool status) public onlyOwner {
+ function setNftCollectionIsAllowed(address collection, bool status) external onlyOwner {
nftCollectionAllowList[collection] = status;
emit AllowListSet(collection, status);
}
@@ -109,7 +111,7 @@
address _collection,
uint256 _token,
uint128 _pieces
- ) public {
+ ) external {
require(rftCollection != address(0), "RFT collection is not set");
UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);
require(
@@ -148,7 +150,7 @@
/// Throws if `msg.sender` isn't owner of all RFT token pieces.
/// @param _collection RFT collection address
/// @param _token id of RFT token
- function rft2nft(address _collection, uint256 _token) public {
+ function rft2nft(address _collection, uint256 _token) external {
require(rftCollection != address(0), "RFT collection is not set");
require(rftCollection == _collection, "Wrong RFT collection");
UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);
tests/src/eth/payable.test.tsdiffbeforeafterboth--- a/tests/src/eth/payable.test.ts
+++ b/tests/src/eth/payable.test.ts
@@ -140,16 +140,13 @@
});
itEth('Fee for nested calls to native methods is withdrawn from the user', async({helper}) => {
- const CONTRACT_BALANCE = 3n * helper.balance.getOneTokenNominal();
+ const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();
const deployer = await helper.eth.createAccountWithBalance(donor);
const caller = await helper.eth.createAccountWithBalance(donor);
const contract = await deployProxyContract(helper, deployer);
-
- const web3 = helper.getWeb3();
- await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS});
- const collectionAddress = (await contract.methods.createNonfungibleCollection().send({from: caller})).events.CollectionCreated.returnValues.collection;
+ const collectionAddress = (await contract.methods.createNonfungibleCollection().send({from: caller, value: Number(CONTRACT_BALANCE)})).events.CollectionCreated.returnValues.collection;
const initialCallerBalance = await helper.balance.getEthereum(caller);
const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
await contract.methods.mintNftToken(collectionAddress).send({from: caller});
@@ -160,22 +157,18 @@
});
itEth('Fee for nested calls to create*Collection methods is withdrawn from the user and from the contract', async({helper}) => {
- const CONTRACT_BALANCE = 3n * helper.balance.getOneTokenNominal();
-
+ const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();
const deployer = await helper.eth.createAccountWithBalance(donor);
const caller = await helper.eth.createAccountWithBalance(donor);
const contract = await deployProxyContract(helper, deployer);
-
- const web3 = helper.getWeb3();
- await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS});
const initialCallerBalance = await helper.balance.getEthereum(caller);
const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
- await contract.methods.createNonfungibleCollection().send({from: caller});
+ await contract.methods.createNonfungibleCollection().send({from: caller, value: Number(CONTRACT_BALANCE)});
const finalCallerBalance = await helper.balance.getEthereum(caller);
const finalContractBalance = await helper.balance.getEthereum(contract.options.address);
expect(finalCallerBalance < initialCallerBalance).to.be.true;
- expect(finalContractBalance < initialContractBalance).to.be.true;
+ expect(finalContractBalance == initialContractBalance).to.be.true;
});
async function deployProxyContract(helper: EthUniqueHelper, deployer: string) {
@@ -189,6 +182,8 @@
import {CollectionHelpers} from "../api/CollectionHelpers.sol";
import {UniqueNFT} from "../api/UniqueNFT.sol";
+ error Value(uint256 value);
+
contract ProxyContract {
bool value = false;
address flipper;
@@ -207,30 +202,30 @@
Flipper(flipper).flip();
}
- function createNonfungibleCollection() public {
+ function createNonfungibleCollection() external payable {
address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;
- address nftCollection = CollectionHelpers(collectionHelpers).createNonfungibleCollection("A", "B", "C");
+ address nftCollection = CollectionHelpers(collectionHelpers).createNonfungibleCollection{value: msg.value}("A", "B", "C");
emit CollectionCreated(nftCollection);
}
- function mintNftToken(address collectionAddress) public {
+ function mintNftToken(address collectionAddress) external {
UniqueNFT collection = UniqueNFT(collectionAddress);
uint256 tokenId = collection.nextTokenId();
collection.mint(msg.sender, tokenId);
emit TokenMinted(tokenId);
}
- function getValue() public view returns (bool) {
+ function getValue() external view returns (bool) {
return Flipper(flipper).getValue();
}
}
contract Flipper {
bool value = false;
- function flip() public {
+ function flip() external {
value = !value;
}
- function getValue() public view returns (bool) {
+ function getValue() external view returns (bool) {
return value;
}
}