diff --git a/Cargo.lock b/Cargo.lock index 5a355af99..a09bb941e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2425,7 +2425,7 @@ dependencies = [ [[package]] name = "hydra-dx-runtime" -version = "15.1.0" +version = "16.0.0" dependencies = [ "frame-benchmarking", "frame-executive", @@ -4444,7 +4444,7 @@ dependencies = [ [[package]] name = "pallet-multi-payment-benchmarking" -version = "3.1.0" +version = "4.0.0" dependencies = [ "frame-benchmarking", "frame-support", @@ -4612,7 +4612,7 @@ dependencies = [ [[package]] name = "pallet-transaction-multi-payment" -version = "3.1.0" +version = "4.0.0" dependencies = [ "frame-support", "frame-system", @@ -5247,7 +5247,7 @@ dependencies = [ [[package]] name = "primitives" -version = "4.1.0" +version = "4.2.0" dependencies = [ "frame-support", "frame-system", diff --git a/node/src/chain_spec.rs b/node/src/chain_spec.rs index ef4d5c088..9151625ae 100644 --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -5,9 +5,9 @@ use hydra_dx_runtime::opaque::SessionKeys; use hydra_dx_runtime::pallet_claims::EthereumAddress; use hydra_dx_runtime::{ AccountId, AssetRegistryConfig, AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, ClaimsConfig, CouncilConfig, - ElectionsConfig, FaucetConfig, GenesisConfig, GenesisHistoryConfig, GrandpaConfig, ImOnlineConfig, Perbill, - SessionConfig, Signature, StakerStatus, StakingConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig, - TokensConfig, CORE_ASSET_ID, WASM_BINARY, + ElectionsConfig, FaucetConfig, GenesisConfig, GenesisHistoryConfig, GrandpaConfig, ImOnlineConfig, + MultiTransactionPaymentConfig, Perbill, SessionConfig, Signature, StakerStatus, StakingConfig, SudoConfig, + SystemConfig, TechnicalCommitteeConfig, TokensConfig, CORE_ASSET_ID, WASM_BINARY, }; use pallet_staking::Forcing; use sc_service::ChainType; @@ -317,7 +317,7 @@ fn testnet_genesis( pallet_grandpa: Default::default(), pallet_sudo: SudoConfig { // Assign network admin rights. - key: root_key, + key: root_key.clone(), }, pallet_asset_registry: AssetRegistryConfig { core_asset_id: CORE_ASSET_ID, @@ -335,6 +335,11 @@ fn testnet_genesis( ], next_asset_id: 11, }, + pallet_transaction_multi_payment: MultiTransactionPaymentConfig { + currencies: vec![], + authorities: vec![], + fallback_account: root_key, + }, orml_tokens: TokensConfig { endowed_accounts: endowed_accounts .iter() @@ -470,6 +475,11 @@ fn lerna_genesis( asset_ids: vec![], next_asset_id: 1, }, + pallet_transaction_multi_payment: MultiTransactionPaymentConfig { + currencies: vec![], + authorities: vec![], + fallback_account: hex!["6d6f646c70792f74727372790000000000000000000000000000000000000000"].into(), + }, orml_tokens: TokensConfig { endowed_accounts: endowed_accounts.iter().flat_map(|_x| vec![]).collect(), }, diff --git a/pallets/transaction-multi-payment/Cargo.toml b/pallets/transaction-multi-payment/Cargo.toml index 855fca888..3eda705f2 100644 --- a/pallets/transaction-multi-payment/Cargo.toml +++ b/pallets/transaction-multi-payment/Cargo.toml @@ -6,7 +6,7 @@ homepage = 'https://github.com/galacticcouncil/hydra-dx' license = 'Apache 2.0' name = 'pallet-transaction-multi-payment' repository = 'https://github.com/galacticcouncil/hydra-dx' -version = '3.1.0' +version = '4.0.0' [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] @@ -40,14 +40,15 @@ sp-api = {default-features = false, version = '3.0.0'} sp-core = {default-features = false, version = '3.0.0'} sp-runtime = {default-features = false, version = '3.0.0'} sp-std = {default-features = false, version = '3.0.0'} - pallet-transaction-payment = {default-features = false, version = '3.0.0'} -[dev-dependencies] +# These 2 dependencies are for testing only. But need to be here for benchmarking pallet - could not figure out why yet +pallet-asset-registry = {path = '../asset-registry', default-features = false} pallet-balances = {default-features = false, version = '3.0.0'} + +[dev-dependencies] orml-currencies = {default-features = false, version = "0.4.1-dev"} pallet-xyk = {path = '../xyk', default-features = false} -pallet-asset-registry = {path = '../asset-registry', default-features = false} sp-io = {default-features = false, version = '3.0.0'} [features] @@ -62,4 +63,6 @@ std = [ 'sp-runtime/std', 'orml-tokens/std', 'orml-traits/std', + 'pallet-balances/std', + 'pallet-asset-registry/std', ] diff --git a/pallets/transaction-multi-payment/benchmarking/Cargo.toml b/pallets/transaction-multi-payment/benchmarking/Cargo.toml index 3aed3df72..d14cf1a01 100644 --- a/pallets/transaction-multi-payment/benchmarking/Cargo.toml +++ b/pallets/transaction-multi-payment/benchmarking/Cargo.toml @@ -6,7 +6,7 @@ homepage = 'https://github.com/galacticcouncil/hydra-dx' license = 'Apache 2.0' name = 'pallet-multi-payment-benchmarking' repository = 'https://github.com/galacticcouncil/hydra-dx' -version = '3.1.0' +version = '4.0.0' [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] diff --git a/pallets/transaction-multi-payment/benchmarking/src/lib.rs b/pallets/transaction-multi-payment/benchmarking/src/lib.rs index c5b4dec1f..d626c1de1 100644 --- a/pallets/transaction-multi-payment/benchmarking/src/lib.rs +++ b/pallets/transaction-multi-payment/benchmarking/src/lib.rs @@ -20,11 +20,11 @@ mod mock; use sp_std::prelude::*; +use sp_std::vec; use frame_benchmarking::{account, benchmarks}; use frame_system::RawOrigin; use orml_traits::{MultiCurrency, MultiCurrencyExtended}; -use orml_utilities::OrderedSet; use pallet_transaction_multi_payment::Pallet as MultiPaymentModule; use primitives::{Amount, AssetId, Balance, Price}; @@ -69,7 +69,7 @@ benchmarks! { let maker = funded_account::("maker", 1); initialize_pool::(maker.clone(), ASSET_ID, 1000, Price::from(1))?; MultiPaymentModule::::add_new_member(&maker); - MultiPaymentModule::::add_currency(RawOrigin::Signed(maker).into(), ASSET_ID)?; + MultiPaymentModule::::add_currency(RawOrigin::Signed(maker).into(), ASSET_ID, Price::from(10))?; let caller = funded_account::("caller", 2); MultiPaymentModule::::set_currency(RawOrigin::Signed(caller.clone()).into(), ASSET_ID)?; @@ -83,7 +83,7 @@ benchmarks! { set_currency { let maker = funded_account::("maker", 1); MultiPaymentModule::::add_new_member(&maker); - MultiPaymentModule::::add_currency(RawOrigin::Signed(maker).into(), ASSET_ID)?; + MultiPaymentModule::::add_currency(RawOrigin::Signed(maker).into(), ASSET_ID, Price::from(10))?; let caller = funded_account::("caller", 123); @@ -97,21 +97,24 @@ benchmarks! { add_currency { let caller = funded_account::("maker", 1); MultiPaymentModule::::add_new_member(&caller); - }: { MultiPaymentModule::::add_currency(RawOrigin::Signed(caller.clone()).into(), 10)? } + + let price = Price::from(10); + + }: { MultiPaymentModule::::add_currency(RawOrigin::Signed(caller.clone()).into(), 10, price)? } verify { - assert_eq!(MultiPaymentModule::::currencies(), OrderedSet::from(vec![10])); + assert_eq!(MultiPaymentModule::::currencies(10), Some(price)); } remove_currency { let caller = funded_account::("maker", 1); MultiPaymentModule::::add_new_member(&caller); - MultiPaymentModule::::add_currency(RawOrigin::Signed(caller.clone()).into(), 10)?; + MultiPaymentModule::::add_currency(RawOrigin::Signed(caller.clone()).into(), 10, Price::from(2))?; - assert_eq!(MultiPaymentModule::::currencies(), OrderedSet::from(vec![10])); + assert_eq!(MultiPaymentModule::::currencies(10), Some(Price::from(2))); }: { MultiPaymentModule::::remove_currency(RawOrigin::Signed(caller.clone()).into(), 10)? } verify { - assert_eq!(MultiPaymentModule::::currencies(), OrderedSet::::new()) + assert_eq!(MultiPaymentModule::::currencies(10), None) } add_member{ diff --git a/pallets/transaction-multi-payment/benchmarking/src/mock.rs b/pallets/transaction-multi-payment/benchmarking/src/mock.rs index 00abda8b1..8308f07fd 100644 --- a/pallets/transaction-multi-payment/benchmarking/src/mock.rs +++ b/pallets/transaction-multi-payment/benchmarking/src/mock.rs @@ -38,7 +38,6 @@ use pallet_xyk::AssetPairAccountIdFor; use std::cell::RefCell; use frame_benchmarking::frame_support::weights::Pays; -use orml_utilities::OrderedSet; use primitives::fee; pub type AccountId = u64; @@ -249,8 +248,9 @@ impl ExtBuilder { .unwrap(); pallet_transaction_multi_payment::GenesisConfig:: { - currencies: OrderedSet::from(vec![]), + currencies: vec![], authorities: vec![], + fallback_account: 1000, } .assimilate_storage(&mut t) .unwrap(); diff --git a/pallets/transaction-multi-payment/src/lib.rs b/pallets/transaction-multi-payment/src/lib.rs index 92728d012..fd7e24b1e 100644 --- a/pallets/transaction-multi-payment/src/lib.rs +++ b/pallets/transaction-multi-payment/src/lib.rs @@ -27,6 +27,7 @@ mod mock; #[cfg(test)] mod tests; +mod traits; use frame_support::{ dispatch::DispatchResult, @@ -46,14 +47,13 @@ use sp_std::prelude::*; use pallet_transaction_payment::OnChargeTransaction; use sp_std::marker::PhantomData; +use frame_support::sp_runtime::FixedPointNumber; use frame_support::weights::{Pays, Weight}; use orml_traits::{MultiCurrency, MultiCurrencyExtended}; use primitives::asset::AssetPair; -use primitives::traits::{CurrencySwap, AMM}; +use primitives::traits::AMM; use primitives::{Amount, AssetId, Balance, CORE_ASSET_ID}; -use orml_utilities::OrderedSet; - type NegativeImbalanceOf = ::AccountId>>::NegativeImbalance; // Re-export pallet items so that they can be accessed from the crate namespace. pub use pallet::*; @@ -63,6 +63,7 @@ pub mod pallet { use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::OriginFor; + use primitives::Price; #[pallet::pallet] pub struct Pallet(_); @@ -141,34 +142,50 @@ pub mod pallet { /// Account is not a member of authorities. NotAMember, + + /// Fallback price cannot be zero. + ZeroPrice, + + /// Fallback price was not found. + FallbackPriceNotFound, + + /// Math overflow + Overflow, } /// Account currency map #[pallet::storage] #[pallet::getter(fn get_currency)] - pub type AccountCurrencyMap = StorageMap<_, Blake2_128Concat, T::AccountId, Option, ValueQuery>; + pub type AccountCurrencyMap = StorageMap<_, Blake2_128Concat, T::AccountId, AssetId, OptionQuery>; /// Curated list of currencies which fees can be paid with #[pallet::storage] #[pallet::getter(fn currencies)] - pub type AcceptedCurrencies = StorageValue<_, OrderedSet, ValueQuery>; + pub type AcceptedCurrencies = StorageMap<_, Twox64Concat, AssetId, Price, OptionQuery>; #[pallet::storage] #[pallet::getter(fn authorities)] pub type Authorities = StorageValue<_, Vec, ValueQuery>; + /// Account to use when pool does not exist. + #[pallet::storage] + #[pallet::getter(fn fallback_account)] + pub type FallbackAccount = StorageValue<_, T::AccountId, ValueQuery>; + #[pallet::genesis_config] pub struct GenesisConfig { - pub currencies: OrderedSet, + pub currencies: Vec<(AssetId, Price)>, pub authorities: Vec, + pub fallback_account: T::AccountId, } #[cfg(feature = "std")] impl Default for GenesisConfig { fn default() -> Self { GenesisConfig { - currencies: OrderedSet::new(), authorities: vec![], + currencies: vec![], + fallback_account: Default::default(), } } } @@ -176,8 +193,17 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { + if self.fallback_account == Default::default() { + panic!("Fallback account is not set"); + } + + FallbackAccount::::put(self.fallback_account.clone()); + Authorities::::put(self.authorities.clone()); - AcceptedCurrencies::::put(self.currencies.clone()); + + for (asset, price) in &self.currencies { + AcceptedCurrencies::::insert(asset, price); + } } } #[pallet::call] @@ -197,12 +223,12 @@ pub mod pallet { pub fn set_currency(origin: OriginFor, currency: AssetId) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - if currency == CORE_ASSET_ID || Self::currencies().contains(¤cy) { + if currency == CORE_ASSET_ID || AcceptedCurrencies::::contains_key(¤cy) { if T::MultiCurrency::free_balance(currency, &who) == Balance::zero() { return Err(Error::::ZeroBalance.into()); } - >::insert(who.clone(), Some(currency)); + >::insert(who.clone(), currency); if T::WithdrawFeeForSetCurrency::get() == Pays::Yes { Self::withdraw_set_fee(&who, currency)?; @@ -224,7 +250,7 @@ pub mod pallet { /// /// Emits `CurrencyAdded` event when successful. #[pallet::weight((::WeightInfo::add_currency(), DispatchClass::Normal, Pays::No))] - pub fn add_currency(origin: OriginFor, currency: AssetId) -> DispatchResultWithPostInfo { + pub fn add_currency(origin: OriginFor, currency: AssetId, price: Price) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; ensure!(currency != CORE_ASSET_ID, Error::::CoreAssetNotAllowed); @@ -232,11 +258,15 @@ pub mod pallet { // Only selected accounts can perform this action ensure!(Self::authorities().contains(&who), Error::::NotAllowed); - if AcceptedCurrencies::::mutate(|x| x.insert(currency)) { + AcceptedCurrencies::::try_mutate_exists(currency, |maybe_price| -> DispatchResultWithPostInfo { + if maybe_price.is_some() { + return Err(Error::::AlreadyAccepted.into()); + } + + *maybe_price = Some(price); Self::deposit_event(Event::CurrencyAdded(who, currency)); - return Ok(().into()); - } - Err(Error::::AlreadyAccepted.into()) + Ok(().into()) + }) } /// Remove currency from the list of supported currencies @@ -254,12 +284,17 @@ pub mod pallet { // Only selected accounts can perform this action ensure!(Self::authorities().contains(&who), Error::::NotAllowed); - if AcceptedCurrencies::::mutate(|x| x.remove(¤cy)) { + AcceptedCurrencies::::try_mutate(currency, |x| -> DispatchResultWithPostInfo { + if x.is_none() { + return Err(Error::::UnsupportedCurrency.into()); + } + + *x = None; + Self::deposit_event(Event::CurrencyRemoved(who, currency)); - return Ok(().into()); - } - Err(Error::::UnsupportedCurrency.into()) + Ok(().into()) + }) } /// Add an account as member to list of authorities who can manage list of accepted currencies @@ -303,6 +338,10 @@ pub mod pallet { } impl Pallet { + fn account_currency(who: &T::AccountId) -> AssetId { + Pallet::::get_currency(who).unwrap_or(CORE_ASSET_ID) + } + /// Execute a trade to buy HDX and sell selected currency. pub fn swap_currency(who: &T::AccountId, fee: Balance) -> DispatchResult { // Let's determine currency in which user would like to pay the fee @@ -351,9 +390,34 @@ impl Pallet { } } +use crate::traits::PaymentSwapResult; +use frame_support::dispatch::DispatchError; +use traits::CurrencySwap; + impl CurrencySwap<::AccountId, Balance> for Pallet { - fn swap_currency(who: &T::AccountId, fee: u128) -> DispatchResult { - Self::swap_currency(who, fee) + fn swap(who: &T::AccountId, fee: u128) -> Result { + match Self::account_currency(who) { + CORE_ASSET_ID => Ok(PaymentSwapResult::Native), + currency => { + if T::AMMPool::exists(AssetPair { + asset_in: currency, + asset_out: CORE_ASSET_ID, + }) { + Self::swap_currency(who, fee)?; + Ok(PaymentSwapResult::Swapped) + } else { + // If pool does not exists, let's use the currency fixed price + + let price = Self::currencies(currency).ok_or(Error::::FallbackPriceNotFound)?; + + let amount = price.checked_mul_int(fee).ok_or(Error::::Overflow)?; + + T::MultiCurrency::transfer(currency, who, &Self::fallback_account(), amount)?; + + Ok(PaymentSwapResult::Transferred) + } + } + } } } @@ -396,13 +460,19 @@ where WithdrawReasons::TRANSACTION_PAYMENT | WithdrawReasons::TIP }; - if SW::swap_currency(&who, fee.into()).is_err() { - return Err(InvalidTransaction::Payment.into()); - } - - match C::withdraw(who, fee, withdraw_reason, ExistenceRequirement::KeepAlive) { - Ok(imbalance) => Ok(Some(imbalance)), - Err(_) => Err(InvalidTransaction::Payment.into()), + if let Ok(detail) = SW::swap(&who, fee.into()) { + match detail { + PaymentSwapResult::Transferred => Ok(None), + PaymentSwapResult::Error => Err(InvalidTransaction::Payment.into()), + PaymentSwapResult::Native | PaymentSwapResult::Swapped => { + match C::withdraw(who, fee, withdraw_reason, ExistenceRequirement::KeepAlive) { + Ok(imbalance) => Ok(Some(imbalance)), + Err(_) => Err(InvalidTransaction::Payment.into()), + } + } + } + } else { + Err(InvalidTransaction::Payment.into()) } } diff --git a/pallets/transaction-multi-payment/src/mock.rs b/pallets/transaction-multi-payment/src/mock.rs index c538cbc9a..47e7b741d 100644 --- a/pallets/transaction-multi-payment/src/mock.rs +++ b/pallets/transaction-multi-payment/src/mock.rs @@ -31,7 +31,7 @@ use sp_runtime::{ use frame_support::weights::IdentityFee; use frame_support::weights::Weight; use orml_currencies::BasicCurrencyAdapter; -use primitives::{Amount, AssetId, Balance}; +use primitives::{Amount, AssetId, Balance, Price}; use pallet_xyk::AssetPairAccountIdFor; use std::cell::RefCell; @@ -45,6 +45,7 @@ pub const INITIAL_BALANCE: Balance = 1000_000_000_000_000u128; pub const ALICE: AccountId = 1; pub const BOB: AccountId = 2; +pub const FALLBACK_ACCOUNT: AccountId = 300; pub const HDX: AssetId = 0; pub const SUPPORTED_CURRENCY_NO_BALANCE: AssetId = 2000; @@ -291,8 +292,12 @@ impl ExtBuilder { .unwrap(); crate::GenesisConfig:: { - currencies: OrderedSet::from(vec![SUPPORTED_CURRENCY_NO_BALANCE, SUPPORTED_CURRENCY_WITH_BALANCE]), + currencies: vec![ + (SUPPORTED_CURRENCY_NO_BALANCE, Price::from(1)), + (SUPPORTED_CURRENCY_WITH_BALANCE, Price::from_float(1.5)), + ], authorities: vec![self.payment_authority], + fallback_account: FALLBACK_ACCOUNT, } .assimilate_storage(&mut t) .unwrap(); diff --git a/pallets/transaction-multi-payment/src/tests.rs b/pallets/transaction-multi-payment/src/tests.rs index 550870648..7b3f8864f 100644 --- a/pallets/transaction-multi-payment/src/tests.rs +++ b/pallets/transaction-multi-payment/src/tests.rs @@ -22,7 +22,6 @@ use sp_runtime::traits::SignedExtension; use frame_support::weights::DispatchInfo; use orml_traits::MultiCurrency; -use orml_utilities::OrderedSet; use pallet_balances::Call as BalancesCall; use primitives::Price; @@ -216,29 +215,29 @@ fn fee_payment_non_native_insufficient_balance() { #[test] fn add_new_accepted_currency() { ExtBuilder::default().base_weight(5).build().execute_with(|| { - assert_eq!(PaymentPallet::currencies(), OrderedSet::from(vec![2000, 3000])); - - assert_ok!(PaymentPallet::add_currency(Origin::signed(BOB), 100)); - assert_eq!(PaymentPallet::currencies(), OrderedSet::from(vec![2000, 3000, 100])); + assert_ok!(PaymentPallet::add_currency( + Origin::signed(BOB), + 100, + Price::from_float(1.1) + )); + assert_eq!(PaymentPallet::currencies(100), Some(Price::from_float(1.1))); assert_noop!( - PaymentPallet::add_currency(Origin::signed(ALICE), 1000), + PaymentPallet::add_currency(Origin::signed(ALICE), 1000, Price::from_float(1.2)), Error::::NotAllowed ); assert_noop!( - PaymentPallet::add_currency(Origin::signed(BOB), 100), + PaymentPallet::add_currency(Origin::signed(BOB), 100, Price::from(10)), Error::::AlreadyAccepted ); - assert_eq!(PaymentPallet::currencies(), OrderedSet::from(vec![2000, 3000, 100])); + assert_eq!(PaymentPallet::currencies(100), Some(Price::from_float(1.1))); }); } #[test] fn removed_accepted_currency() { ExtBuilder::default().base_weight(5).build().execute_with(|| { - assert_eq!(PaymentPallet::currencies(), OrderedSet::from(vec![2000, 3000])); - - assert_ok!(PaymentPallet::add_currency(Origin::signed(BOB), 100)); - assert_eq!(PaymentPallet::currencies(), OrderedSet::from(vec![2000, 3000, 100])); + assert_ok!(PaymentPallet::add_currency(Origin::signed(BOB), 100, Price::from(3))); + assert_eq!(PaymentPallet::currencies(100), Some(Price::from(3))); assert_noop!( PaymentPallet::remove_currency(Origin::signed(ALICE), 100), @@ -252,11 +251,12 @@ fn removed_accepted_currency() { assert_ok!(PaymentPallet::remove_currency(Origin::signed(BOB), 100)); + assert_eq!(PaymentPallet::currencies(100), None); + assert_noop!( PaymentPallet::remove_currency(Origin::signed(BOB), 100), Error::::UnsupportedCurrency ); - assert_eq!(PaymentPallet::currencies(), OrderedSet::from(vec![2000, 3000])); }); } @@ -298,3 +298,69 @@ fn add_member() { ); }); } + +#[test] +fn fee_payment_in_non_native_currency_with_no_pool() { + const CHARLIE: AccountId = 5; + + ExtBuilder::default() + .base_weight(5) + .account_native_balance(CHARLIE, 0) + .account_tokens(CHARLIE, SUPPORTED_CURRENCY_WITH_BALANCE, 1000) + .build() + .execute_with(|| { + // Make sure Charlie ain't got a penny! + assert_eq!(Balances::free_balance(CHARLIE), 0); + + assert_ok!(PaymentPallet::set_currency( + Origin::signed(CHARLIE), + SUPPORTED_CURRENCY_WITH_BALANCE + )); + + let len = 10; + let info = DispatchInfo { + weight: 5, + ..Default::default() + }; + + assert!(ChargeTransactionPayment::::from(0) + .pre_dispatch(&CHARLIE, CALL, &info, len) + .is_ok()); + + //Native balance check - Charlie should be still broke! + assert_eq!(Balances::free_balance(CHARLIE), 0); + + // token check should be less by the fee amount and -1 as fee in amm swap + assert_eq!(Tokens::free_balance(SUPPORTED_CURRENCY_WITH_BALANCE, &CHARLIE), 970); + assert_eq!(Tokens::free_balance(SUPPORTED_CURRENCY_WITH_BALANCE, &FALLBACK_ACCOUNT), 30); + }); +} + +#[test] +fn fee_payment_non_native_insufficient_balance_with_no_pool() { + const CHARLIE: AccountId = 5; + + ExtBuilder::default() + .base_weight(5) + .account_native_balance(CHARLIE, 0) + .account_tokens(CHARLIE, SUPPORTED_CURRENCY_WITH_BALANCE, 10) + .build() + .execute_with(|| { + assert_ok!(PaymentPallet::set_currency( + Origin::signed(CHARLIE), + SUPPORTED_CURRENCY_WITH_BALANCE + )); + + let len = 10; + let info = DispatchInfo { + weight: 5, + ..Default::default() + }; + + assert!(ChargeTransactionPayment::::from(0) + .pre_dispatch(&CHARLIE, CALL, &info, len) + .is_err()); + + assert_eq!(Tokens::free_balance(SUPPORTED_CURRENCY_WITH_BALANCE, &CHARLIE), 10); + }); +} diff --git a/pallets/transaction-multi-payment/src/traits.rs b/pallets/transaction-multi-payment/src/traits.rs new file mode 100644 index 000000000..619d33d04 --- /dev/null +++ b/pallets/transaction-multi-payment/src/traits.rs @@ -0,0 +1,11 @@ +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum PaymentSwapResult { + Native, + Error, + Swapped, + Transferred, +} + +pub trait CurrencySwap { + fn swap(who: &AccountId, fee: Balance) -> Result; +} diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index e378ae201..5471f7b34 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -2,7 +2,7 @@ authors = ['GalacticCouncil'] edition = '2018' name = 'primitives' -version = '4.1.0' +version = '4.2.0' [build-dependencies] substrate-wasm-builder = {package = 'substrate-wasm-builder', version = '3.0.0'} diff --git a/primitives/src/traits.rs b/primitives/src/traits.rs index 269adeee4..8b43abf72 100644 --- a/primitives/src/traits.rs +++ b/primitives/src/traits.rs @@ -18,7 +18,6 @@ #![allow(clippy::upper_case_acronyms)] use frame_support::dispatch; -use frame_support::dispatch::DispatchResult; use sp_std::vec::Vec; /// Hold information to perform amm transfer @@ -107,7 +106,3 @@ pub trait Resolver { /// Intention ```intention``` must be validated prior to call this function. fn resolve_matched_intentions(pair_account: &AccountId, intention: &Intention, matched: &[Intention]); } - -pub trait CurrencySwap { - fn swap_currency(who: &AccountId, fee: Balance) -> DispatchResult; -} diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 9be3d7080..b946b748e 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -5,7 +5,7 @@ homepage = 'https://github.com/galacticcouncil/hydradx-node' license = 'Apache 2.0' name = 'hydra-dx-runtime' repository = 'https://github.com/galacticcouncil/hydradx-node' -version = '15.1.0' +version = '16.0.0' [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index e8498bcd0..6e09e5e94 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -148,8 +148,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("hydra-dx"), impl_name: create_runtime_str!("hydra-dx"), authoring_version: 1, - spec_version: 15, - impl_version: 2, + spec_version: 16, + impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, }; @@ -1009,7 +1009,7 @@ construct_runtime!( Claims: pallet_claims::{Pallet, Call, Storage, Event, Config}, Exchange: pallet_exchange::{Pallet, Call, Storage, Event}, Faucet: pallet_faucet::{Pallet, Call, Storage, Config, Event}, - MultiTransactionPayment: pallet_transaction_multi_payment::{Pallet, Call, Storage, Event}, + MultiTransactionPayment: pallet_transaction_multi_payment::{Pallet, Call, Config, Storage, Event}, GenesisHistory: pallet_genesis_history::{Pallet, Storage, Config}, } );