--- a/Cargo.lock +++ b/Cargo.lock @@ -3737,6 +3737,7 @@ "frame-support", "frame-system", "log", + "pallet-contracts", "pallet-transaction-payment", "parity-scale-codec", "serde", --- a/pallets/nft/Cargo.toml +++ b/pallets/nft/Cargo.toml @@ -73,6 +73,13 @@ branch = 'v2.0.0_release' optional = true +[dependencies.pallet-contracts] +default-features = false +git = 'https://github.com/usetech-llc/substrate.git' +package = 'pallet-contracts' +branch = 'v2.0.0_release' +version = '2.0.0' + [features] default = ['std'] std = [ --- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -11,6 +11,7 @@ construct_runtime, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure, parameter_types, + debug, traits::{ Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced, Randomness, WithdrawReason, @@ -22,6 +23,7 @@ }, IsSubType, StorageValue, }; +use sp_runtime::print; // use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight}; use frame_system::{self as system, ensure_signed, ensure_root}; @@ -205,7 +207,7 @@ fn set_offchain_schema() -> Weight; } -pub trait Trait: system::Trait + Sized { +pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait { type Event: From> + Into<::Event>; /// Weight information for extrinsics in this pallet. @@ -1737,11 +1739,11 @@ /// Require the transactor pay for themselves and maybe include a tip to gain additional priority /// in the queue. #[derive(Encode, Decode, Clone, Eq, PartialEq)] -pub struct ChargeTransactionPayment( - #[codec(compact)] BalanceOf, +pub struct ChargeTransactionPayment( + #[codec(compact)] BalanceOf ); -impl sp_std::fmt::Debug +impl sp_std::fmt::Debug for ChargeTransactionPayment { #[cfg(feature = "std")] @@ -1754,10 +1756,9 @@ } } -impl ChargeTransactionPayment +impl ChargeTransactionPayment where - T::Call: - Dispatchable + IsSubType>, + T::Call: Dispatchable + IsSubType>, BalanceOf: Send + Sync + FixedPointOperand, { /// utility constructor. Used only in client/factory code. @@ -1787,11 +1788,12 @@ // Set fee based on call type. Creating collection costs 1 Unique. // All other transactions have traditional fees so far - let fee = match call.is_sub_type() { - Some(Call::create_collection(..)) => >::from(1_000_000_000), - _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes - // _ => >::from(100) - }; + // let fee = match call.is_sub_type() { + // Some(Call::create_collection(..)) => >::from(1_000_000_000), + // _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes + // // _ => >::from(100) + // }; + let fee = Self::traditional_fee(len, info, tip); // Determine who is paying transaction fee based on ecnomic model // Parse call to extract collection ID and access collection sponsor @@ -1861,6 +1863,11 @@ } } + // Some(pallet_contracts::Call::call(_dest, _value, _gas_limit, _data)) => { + // Some(pallet_contracts::Call::call(..)) => { + // T::AccountId::default() + // } + _ => T::AccountId::default(), }; @@ -1890,7 +1897,8 @@ } } -impl SignedExtension + +impl SignedExtension for ChargeTransactionPayment where BalanceOf: Send + Sync + From + FixedPointOperand, @@ -1900,12 +1908,13 @@ type AccountId = T::AccountId; type Call = T::Call; type AdditionalSigned = (); - type Pre = ( - BalanceOf, - Self::AccountId, - Option>, - BalanceOf, - ); + type Pre = (); + // type Pre = ( + // BalanceOf, + // Self::AccountId, + // Option>, + // BalanceOf, + // ); fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { Ok(()) } @@ -1919,11 +1928,9 @@ ) -> TransactionValidity { let (fee, _) = self.withdraw_fee(who, call, info, len)?; - let mut r = ValidTransaction::default(); - // NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which - // will be a bit more than setting the priority to tip. For now, this is enough. - r.priority = fee.saturated_into::(); - Ok(r) + print("====== validate"); + + Ok(ValidTransaction::default()) } fn pre_dispatch( @@ -1933,8 +1940,15 @@ info: &DispatchInfoOf, len: usize, ) -> Result { - let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?; - Ok((self.0, who.clone(), imbalance, fee)) + + print("========= PreDispatch"); + + // let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?; + + // debug::info!("Fee: {:?}", fee); + + // Ok((self.0, who.clone(), imbalance, fee)) + Ok(()) } fn post_dispatch( @@ -1944,36 +1958,223 @@ len: usize, _result: &DispatchResult, ) -> Result<(), TransactionValidityError> { - let (tip, who, imbalance, fee) = pre; - if let Some(payed) = imbalance { - let actual_fee = >::compute_actual_fee( - len as u32, info, post_info, tip, - ); - let refund = fee.saturating_sub(actual_fee); - let actual_payment = - match ::Currency::deposit_into_existing( - &who, refund, - ) { - Ok(refund_imbalance) => { - // The refund cannot be larger than the up front payed max weight. - // `PostDispatchInfo::calc_unspent` guards against such a case. - match payed.offset(refund_imbalance) { - Ok(actual_payment) => actual_payment, - Err(_) => return Err(InvalidTransaction::Payment.into()), - } - } - // We do not recreate the account using the refund. The up front payment - // is gone in that case. - Err(_) => payed, - }; - let imbalances = actual_payment.split(tip); - ::OnTransactionPayment::on_unbalanceds( - Some(imbalances.0).into_iter().chain(Some(imbalances.1)), - ); - } + // let (tip, who, imbalance, fee) = pre; + // if let Some(payed) = imbalance { + // let actual_fee = >::compute_actual_fee( + // len as u32, info, post_info, tip, + // ); + // let refund = fee.saturating_sub(actual_fee); + // let actual_payment = + // match ::Currency::deposit_into_existing( + // &who, refund, + // ) { + // Ok(refund_imbalance) => { + // // The refund cannot be larger than the up front payed max weight. + // // `PostDispatchInfo::calc_unspent` guards against such a case. + // match payed.offset(refund_imbalance) { + // Ok(actual_payment) => actual_payment, + // Err(_) => return Err(InvalidTransaction::Payment.into()), + // } + // } + // // We do not recreate the account using the refund. The up front payment + // // is gone in that case. + // Err(_) => payed, + // }; + // let imbalances = actual_payment.split(tip); + // ::OnTransactionPayment::on_unbalanceds( + // Some(imbalances.0).into_iter().chain(Some(imbalances.1)), + // ); + // } + Ok(()) + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#[derive(Encode, Decode, Clone, Eq, PartialEq)] +pub struct ChargeContractTransactionPayment( + #[codec(compact)] BalanceOf +); + +impl sp_std::fmt::Debug + for ChargeContractTransactionPayment +{ + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "ChargeContractTransactionPayment<{:?}>", self.0) + } + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { Ok(()) } } + +// impl ChargeContractTransactionPayment +// where +// // T::Call: Dispatchable, +// T::Call: Dispatchable + IsSubType>, +// BalanceOf: Send + Sync + FixedPointOperand, +// { +// // /// utility constructor. Used only in client/factory code. +// // pub fn from(fee: BalanceOf) -> Self { +// // Self(fee) +// // } + +// pub fn traditional_fee( +// len: usize, +// info: &DispatchInfoOf, +// tip: BalanceOf, +// ) -> BalanceOf +// where +// T::Call: Dispatchable, +// { +// >::compute_fee(len as u32, info, tip) +// } + +// fn withdraw_fee( +// &self, +// who: &T::AccountId, +// call: &T::Call, +// info: &DispatchInfoOf, +// len: usize, +// ) -> Result<(BalanceOf, Option>), TransactionValidityError> { +// let tip = self.0; + +// let mut fee = Self::traditional_fee(len, info, tip); + +// // Determine who is paying transaction fee based on ecnomic model +// // Parse call to extract collection ID and access collection sponsor +// // let sponsor: T::AccountId = match call.is_sub_type() { +// // // Some(pallet_contracts::Call::call(_dest, _value, _gas_limit, _data)) => { +// // Some(pallet_contracts::Call::call(..)) => { +// // // fee = >::from(0); +// // T::AccountId::default() +// // } +// // _ => T::AccountId::default(), +// // }; +// let sponsor = T::AccountId::default(); + +// let mut who_pays_fee: T::AccountId = sponsor.clone(); +// if sponsor == T::AccountId::default() { +// who_pays_fee = who.clone(); +// } + +// // Only mess with balances if fee is not zero. +// if fee.is_zero() { +// return Ok((fee, None)); +// } + +// match ::Currency::withdraw( +// &who_pays_fee, +// fee, +// if tip.is_zero() { +// WithdrawReason::TransactionPayment.into() +// } else { +// WithdrawReason::TransactionPayment | WithdrawReason::Tip +// }, +// ExistenceRequirement::KeepAlive, +// ) { +// Ok(imbalance) => Ok((fee, Some(imbalance))), +// Err(_) => Err(InvalidTransaction::Payment.into()), +// } +// } +// } + + + +impl SignedExtension + for ChargeContractTransactionPayment +where + BalanceOf: Send + Sync + From + FixedPointOperand, + // T::Call: Dispatchable, + T::Call: Dispatchable + IsSubType>, +{ + const IDENTIFIER: &'static str = "ChargeContractTransactionPayment"; + type AccountId = T::AccountId; + type Call = T::Call; + type AdditionalSigned = (); + type Pre = (); + + // type Pre = ( + // BalanceOf, + // Self::AccountId, + // Option>, + // BalanceOf, + // ); + fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { + Ok(()) + } + + fn validate( + &self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> TransactionValidity { + // let (fee, _) = self.withdraw_fee(who, call, info, len)?; + + print("====== Contracts validate"); + + Ok(ValidTransaction::default()) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + // let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?; + // Ok((self.0, who.clone(), imbalance, fee)) + + print("====== Contracts pre-dispatch"); + // debug::info!("Fee: {:?}", fee); + + Ok(()) + } + + fn post_dispatch( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + len: usize, + _result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + // let (tip, who, imbalance, fee) = pre; + // if let Some(payed) = imbalance { + // let actual_fee = >::compute_actual_fee( + // len as u32, info, post_info, tip, + // ); + // let refund = fee.saturating_sub(actual_fee); + // let actual_payment = + // match ::Currency::deposit_into_existing( + // &who, refund, + // ) { + // Ok(refund_imbalance) => { + // // The refund cannot be larger than the up front payed max weight. + // // `PostDispatchInfo::calc_unspent` guards against such a case. + // match payed.offset(refund_imbalance) { + // Ok(actual_payment) => actual_payment, + // Err(_) => return Err(InvalidTransaction::Payment.into()), + // } + // } + // // We do not recreate the account using the refund. The up front payment + // // is gone in that case. + // Err(_) => payed, + // }; + // let imbalances = actual_payment.split(tip); + // ::OnTransactionPayment::on_unbalanceds( + // Some(imbalances.0).into_iter().chain(Some(imbalances.1)), + // ); + // } + Ok(()) + } +} + + // #endregion --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -352,6 +352,7 @@ system::CheckNonce, system::CheckWeight, pallet_nft::ChargeTransactionPayment, + pallet_nft::ChargeContractTransactionPayment, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic;