From c8be66f6b51754836bd5ac42d429be8f279a6d98 Mon Sep 17 00:00:00 2001 From: str-mv <51784859+str-mv@users.noreply.github.com> Date: Fri, 06 Nov 2020 06:16:51 +0000 Subject: [PATCH] Merge pull request #14 from usetech-llc/feature/NFTPAR-109-110_contract_sponsoring Feature/nftpar 109 110 contract sponsoring --- --- 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/default_weights.rs +++ b/pallets/nft/src/default_weights.rs @@ -92,4 +92,9 @@ .saturating_add(DbWeight::get().reads(2 as Weight)) .saturating_add(DbWeight::get().writes(1 as Weight)) } + // fn enable_contract_sponsoring() -> Weight { + // (0 as Weight) + // .saturating_add(DbWeight::get().reads(1 as Weight)) + // .saturating_add(DbWeight::get().writes(1 as Weight)) + // } } --- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -28,15 +28,15 @@ use sp_runtime::sp_std::prelude::Vec; use sp_runtime::{ traits::{ - DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SaturatedConversion, Saturating, - SignedExtension, Zero, + DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SignedExtension, Zero, }, transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError, - ValidTransaction, + InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, }, FixedPointOperand, FixedU128, }; +use pallet_contracts::ContractAddressFor; +use sp_runtime::traits::StaticLookup; #[cfg(test)] mod mock; @@ -203,9 +203,10 @@ fn approve() -> Weight; fn transfer_from() -> Weight; fn set_offchain_schema() -> Weight; + // fn enable_contract_sponsoring() -> 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. @@ -257,9 +258,9 @@ pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => Vec>; pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber; - // Sponsorship - pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId; - pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId; + // Contract Sponsorship and Ownership + pub ContractOwner get(fn contract_owner): map hasher(identity) T::AccountId => T::AccountId; + pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(identity) T::AccountId => bool; } add_extra_genesis { build(|config: &GenesisConfig| { @@ -1112,7 +1113,37 @@ ensure_root(origin)?; ::put(limits); Ok(()) - } + } + + /// Enable smart contract self-sponsoring. + /// + /// # Permissions + /// + /// * Contract Owner + /// + /// # Arguments + /// + /// * contract address + /// * enable flag + /// + #[weight = 0] + pub fn enable_contract_sponsoring( + origin, + contract_address: T::AccountId, + enable: bool + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + let mut is_owner = false; + if >::contains_key(contract_address.clone()) { + let owner = >::get(&contract_address); + is_owner = sender == owner; + } + ensure!(is_owner, "Only contract owner may call this method"); + + >::insert(contract_address, enable); + Ok(()) + } + } } @@ -1737,11 +1768,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 +1785,9 @@ } } -impl ChargeTransactionPayment +impl ChargeTransactionPayment where - T::Call: - Dispatchable + IsSubType>, + T::Call: Dispatchable + IsSubType> + IsSubType>, BalanceOf: Send + Sync + FixedPointOperand, { /// utility constructor. Used only in client/factory code. @@ -1787,15 +1817,16 @@ // 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 - let sponsor: T::AccountId = match call.is_sub_type() { + let mut sponsor: T::AccountId = match IsSubType::>::is_sub_type(call) { Some(Call::create_item(collection_id, _properties, _owner)) => { >::get(collection_id).sponsor } @@ -1864,6 +1895,39 @@ _ => T::AccountId::default(), }; + // Sponsor smart contracts + sponsor = match IsSubType::>::is_sub_type(call) { + + // On instantiation: set the contract owner + Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => { + + let new_contract_address = ::DetermineContractAddress::contract_address_for( + code_hash, + &data, + &who, + ); + >::insert(new_contract_address.clone(), who.clone()); + + T::AccountId::default() + }, + + // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is + Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => { + + let mut sp = T::AccountId::default(); + let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default()); + if >::contains_key(called_contract.clone()) { + if >::get(called_contract.clone()) { + sp = called_contract; + } + } + + sp + }, + + _ => sponsor, + }; + let mut who_pays_fee: T::AccountId = sponsor.clone(); if sponsor == T::AccountId::default() { who_pays_fee = who.clone(); @@ -1890,11 +1954,12 @@ } } -impl SignedExtension + +impl SignedExtension for ChargeTransactionPayment where BalanceOf: Send + Sync + From + FixedPointOperand, - T::Call: Dispatchable + IsSubType>, + T::Call: Dispatchable + IsSubType> + IsSubType>, { const IDENTIFIER: &'static str = "ChargeTransactionPayment"; type AccountId = T::AccountId; @@ -1912,18 +1977,12 @@ fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, ) -> 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) + Ok(ValidTransaction::default()) } fn pre_dispatch( @@ -1974,6 +2033,7 @@ Ok(()) } } + // #endregion -- gitstuff