From 0482d99c2ac0eb866f799abc8b1b766c52600a30 Mon Sep 17 00:00:00 2001 From: zktony Date: Tue, 14 Nov 2023 01:47:17 +0530 Subject: [PATCH 1/5] Added test cases --- pallets/thea-executor/src/lib.rs | 66 ++++++++++---- pallets/thea-executor/src/mock.rs | 5 ++ pallets/thea-executor/src/tests.rs | 139 +++++++++++++++++++++++++++++ primitives/polkadex/src/assets.rs | 14 +++ runtimes/mainnet/src/lib.rs | 3 + 5 files changed, 209 insertions(+), 18 deletions(-) diff --git a/pallets/thea-executor/src/lib.rs b/pallets/thea-executor/src/lib.rs index 47b565661..44067d242 100644 --- a/pallets/thea-executor/src/lib.rs +++ b/pallets/thea-executor/src/lib.rs @@ -22,6 +22,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate core; + use frame_support::pallet_prelude::Weight; pub use pallet::*; @@ -44,10 +46,19 @@ pub trait WeightInfo { #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{pallet_prelude::*, sp_runtime::SaturatedConversion, traits::{fungible::Mutate, fungibles::Inspect, tokens::Preservation}, transactional}; + use frame_support::{ + pallet_prelude::*, + sp_runtime::SaturatedConversion, + traits::{ + fungible::Mutate, + fungibles::{Inspect, Mutate as OtherMutate}, + tokens::Preservation, + }, + transactional, + }; use frame_system::pallet_prelude::*; use pallet_asset_conversion::Swap; - use polkadex_primitives::Resolver; + use polkadex_primitives::{AssetId, Resolver}; use sp_runtime::{traits::AccountIdConversion, Saturating}; use sp_std::vec::Vec; use thea_primitives::{ @@ -62,7 +73,7 @@ pub mod pallet { /// Configure the pallet by specifying the parameters and types on which it depends. #[pallet::config] - pub trait Config: frame_system::Config { + pub trait Config: frame_system::Config + pallet_asset_conversion::Config { /// Because this pallet emits events, it depends on the Runtime's definition of an /// event. type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -81,6 +92,14 @@ pub mod pallet { + MaxEncodedLen + Into<<::Assets as Inspect>::AssetId> + From; + type MultiAssetIdAdapter: From + + Into<::MultiAssetId>; + + type AssetBalanceAdapter: Into<::AssetBalance> + + Copy + + From<::AssetBalance> + + From + + Into; /// Asset Create/ Update Origin type AssetCreateUpdateOrigin: EnsureOrigin<::RuntimeOrigin>; /// Something that executes the payload @@ -99,6 +118,9 @@ pub mod pallet { /// Total Withdrawals #[pallet::constant] type WithdrawalSize: Get; + /// Total Withdrawals + #[pallet::constant] + type ExistentialDeposit: Get; /// Para Id type ParaId: Get; /// Type representing the weight of this pallet @@ -222,6 +244,7 @@ pub mod pallet { impl Pallet { #[pallet::call_index(0)] #[pallet::weight(::WeightInfo::withdraw(1))] + #[transactional] pub fn withdraw( origin: OriginFor, asset_id: u128, @@ -366,6 +389,7 @@ pub mod pallet { T::TheaPalletId::get().into_account_truncating() } + #[transactional] pub fn do_withdraw( user: T::AccountId, asset_id: u128, @@ -377,10 +401,8 @@ pub mod pallet { ) -> Result<(), DispatchError> { ensure!(beneficiary.len() <= 1000, Error::::BeneficiaryTooLong); ensure!(network != 0, Error::::WrongNetwork); - let mut pending_withdrawals = >::get(network); let metadata = >::get(asset_id).ok_or(Error::::AssetNotRegistered)?; - ensure!( pending_withdrawals.len() < T::WithdrawalSize::get() as usize, Error::::WithdrawalNotAllowed @@ -405,7 +427,6 @@ pub mod pallet { polkadex_primitives::AssetId::Asset(asset_id), polkadex_primitives::AssetId::Polkadex ]; - let token_taken = T::Swap::swap_tokens_for_exact_tokens( user.clone(), path, @@ -414,8 +435,8 @@ pub mod pallet { Self::thea_account(), false, )?; - amount = amount.saturating_sub(token_taken.saturated_into()); + ensure!(amount > 0, Error::::AmountCannotBeZero); } else { // Pay the fees ::Currency::transfer( @@ -485,6 +506,7 @@ pub mod pallet { Ok(()) } + #[transactional] pub fn execute_deposit( deposit: Deposit, recipient: &T::AccountId, @@ -499,24 +521,32 @@ pub mod pallet { polkadex_primitives::AssetId::Asset(deposit.asset_id), polkadex_primitives::AssetId::Polkadex ]; - + let amount_out: T::AssetBalanceAdapter = T::ExistentialDeposit::get().into(); + let asset1: T::MultiAssetIdAdapter = + polkadex_primitives::AssetId::Asset(deposit.asset_id).into(); + let asset2: T::MultiAssetIdAdapter = polkadex_primitives::AssetId::Polkadex.into(); + let fee_amount: T::AssetBalanceAdapter = pallet_asset_conversion::pallet::Pallet:: + ::quote_price_tokens_for_exact_tokens(asset1.into(), asset2.into(), amount_out.into(), true) + .ok_or(Error::::CannotSwapForFees)?.into(); + let fee_amount: u128 = fee_amount.into(); + ensure!(fee_amount <= deposit_amount, Error::::AmountCannotBeZero); + Self::resolve_mint(&Self::thea_account(), deposit.asset_id.into(), fee_amount)?; + T::Swap::swap_tokens_for_exact_tokens( + Self::thea_account(), + path, + amount_out.into(), + None, + recipient.clone(), + false, + )?; Self::resolver_deposit( deposit.asset_id.into(), - deposit_amount, + deposit_amount.saturating_sub(fee_amount), recipient, Self::thea_account(), 1u128, Self::thea_account(), )?; - - T::Swap::swap_tokens_for_exact_tokens( - recipient.clone(), - path, - sp_runtime::traits::One::one(), - None, - recipient.clone(), - false, - )?; } else { Self::resolver_deposit( deposit.asset_id.into(), diff --git a/pallets/thea-executor/src/mock.rs b/pallets/thea-executor/src/mock.rs index f030a2395..626c42dfd 100644 --- a/pallets/thea-executor/src/mock.rs +++ b/pallets/thea-executor/src/mock.rs @@ -186,8 +186,10 @@ parameter_types! { pub const PolkadexAssetId: u128 = 0; pub const ParaId: u32 = 2040; } +use polkadex_primitives::AssetId; use sp_core::ConstU32; use sp_runtime::Permill; + impl thea_executor::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -201,6 +203,9 @@ impl thea_executor::Config for Test { type ParaId = ParaId; type WeightInfo = crate::weights::WeightInfo; type Swap = AssetConversion; + type MultiAssetIdAdapter = AssetId; + type AssetBalanceAdapter = u128; + type ExistentialDeposit = ExistentialDeposit; } impl frame_system::offchain::SendTransactionTypes for Test diff --git a/pallets/thea-executor/src/tests.rs b/pallets/thea-executor/src/tests.rs index bbabb4335..ceb7b9792 100644 --- a/pallets/thea-executor/src/tests.rs +++ b/pallets/thea-executor/src/tests.rs @@ -341,3 +341,142 @@ fn test_update_asset_metadata_full() { assert_last_event::(Event::::AssetMetadataSet(md).into()); }) } + +#[test] +fn test_resolve_deposit() { + new_test_ext().execute_with(|| { + let asset_id = 2000u128; + let admin = 1u64; + let recipient = 2u64; + Balances::set_balance(&admin, 1_000_000_000_000_000_000); + assert_ok!(Assets::create( + RuntimeOrigin::signed(admin), + parity_scale_codec::Compact(asset_id), + admin, + 1u128 + )); + assert_ok!(TheaExecutor::update_asset_metadata(RuntimeOrigin::root(), asset_id, 12)); + Balances::set_balance(&recipient, 1_000_000_000_000_000_000); + let deposit = Deposit { + id: Vec::new(), + recipient, + asset_id, + amount: 1_000_000_000_000_000_000u128, + extra: vec![], + }; + assert_ok!(TheaExecutor::execute_deposit(deposit, &recipient)); + }) +} + +#[test] +fn test_deposit_without_account() { + new_test_ext().execute_with(|| { + setup_pool(); + let asset_id = 1u128; + let admin = 1u64; + let recipient = 2u64; + Balances::set_balance(&admin, 1_000_000_000_000_000_000); + assert_ok!(TheaExecutor::update_asset_metadata(RuntimeOrigin::root(), asset_id, 12)); + Balances::set_balance(&TheaExecutor::thea_account(), 1_000_000_000_000_000_000); + let deposit = Deposit { + id: Vec::new(), + recipient, + asset_id, + amount: 1_000_000_000_000_000u128, + extra: vec![], + }; + assert_ok!(TheaExecutor::execute_deposit(deposit, &recipient)); + assert_eq!(Balances::free_balance(&recipient), 50); + assert_eq!(Assets::balance(asset_id, &recipient), 999_999_994_984_954u128); + assert_eq!(Assets::balance(asset_id, &TheaExecutor::thea_account()), 0u128); + assert_eq!( + Balances::free_balance(&TheaExecutor::thea_account()), + 1_000_000_000_000_000_000 + ); + }) +} + +#[test] +fn test_do_withdrawal() { + new_test_ext().execute_with(|| { + setup_pool(); + let sender = 2u64; + let asset_id = 1u128; + // Set asset balance + Balances::set_balance(&sender, 1_000_000_000_000_000_000); + Assets::mint_into(asset_id, &sender, 1_000_000_000_000_000_000); + // Set withdrawal Fee + assert_ok!(TheaExecutor::set_withdrawal_fee(RuntimeOrigin::root(), 1, 100)); + assert_ok!(TheaExecutor::update_asset_metadata(RuntimeOrigin::root(), asset_id, 12)); + assert_ok!(TheaExecutor::withdraw( + RuntimeOrigin::signed(sender), + asset_id, + 1_000_000_000_000_000u128, + vec![1; 32], + true, + 1, + true + )); + assert_eq!(Balances::free_balance(&sender), 1_000_000_000_000_000_000); + assert_eq!(Assets::balance(asset_id, &sender), 999_000_000_000_000_000); + assert_eq!(Balances::free_balance(&TheaExecutor::thea_account()), 1_000u128); + }) +} + +#[test] +fn test_do_withdrawal_with_total_amount_consumed_returns_error() { + new_test_ext().execute_with(|| { + setup_pool(); + let sender = 2u64; + let asset_id = 1u128; + // Set asset balance + Balances::set_balance(&sender, 1_000_000_000_000_000_000); + Assets::mint_into(asset_id, &sender, 100_300_903u128); + // Set withdrawal Fee + assert_ok!(TheaExecutor::set_withdrawal_fee(RuntimeOrigin::root(), 1, 100)); + assert_ok!(TheaExecutor::update_asset_metadata(RuntimeOrigin::root(), asset_id, 12)); + assert_noop!( + TheaExecutor::withdraw( + RuntimeOrigin::signed(sender), + asset_id, + 1_000_000_000_000_000u128, + vec![1; 32], + true, + 1, + true + ), + sp_runtime::TokenError::FundsUnavailable + ); + }) +} + +fn setup_pool() { + let asset_id = 1u128; + let admin = 1u64; + Balances::set_balance(&admin, 2_000_000_000_000_000_000_000_000_000_000u128); + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + parity_scale_codec::Compact(asset_id), + admin, + false, + 1u128 + )); + // Mint tokens + Assets::mint_into(asset_id, &admin, 1_000_000_000_000_000_000_000_000_000u128).unwrap(); + // Create pool + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(admin), + polkadex_primitives::AssetId::Asset(asset_id), + polkadex_primitives::AssetId::Polkadex + )); + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(admin), + polkadex_primitives::AssetId::Asset(asset_id), + polkadex_primitives::AssetId::Polkadex, + 1_000_000_000_000_000_000_000u128, + 10_000_000_000_000_000u128, + 1u128, + 1u128, + admin + )); +} diff --git a/primitives/polkadex/src/assets.rs b/primitives/polkadex/src/assets.rs index 522efe1fe..78a7cd83a 100644 --- a/primitives/polkadex/src/assets.rs +++ b/primitives/polkadex/src/assets.rs @@ -136,6 +136,19 @@ pub trait Resolver< } Ok(()) } + + fn resolve_mint( + recipeint: &AccountId, + asset: AssetId, + amount: Balance, + ) -> Result<(), DispatchError> { + if asset == NativeAssetId::get() { + return Err(DispatchError::Other("Cannot mint Native Asset")) + } else { + Others::mint_into(asset.into(), recipeint, amount.saturated_into())?; + } + Ok(()) + } } /// Enumerated asset on chain @@ -158,6 +171,7 @@ pub enum AssetId { Asset(u128), Polkadex, } + use sp_runtime::traits::Zero; impl From for AssetId { fn from(value: u128) -> Self { diff --git a/runtimes/mainnet/src/lib.rs b/runtimes/mainnet/src/lib.rs index 0f23f2e46..cdb480b87 100644 --- a/runtimes/mainnet/src/lib.rs +++ b/runtimes/mainnet/src/lib.rs @@ -1364,6 +1364,9 @@ impl thea_executor::Config for Runtime { type ParaId = ParaId; type WeightInfo = thea_executor::weights::WeightInfo; type Swap = AssetConversion; + type MultiAssetIdAdapter = AssetId; + type AssetBalanceAdapter = u128; + type ExistentialDeposit = ExistentialDeposit; } #[cfg(feature = "runtime-benchmarks")] From f97fe09817888a1bf8c4e1ef78b5a1c8c39147e6 Mon Sep 17 00:00:00 2001 From: zktony Date: Tue, 14 Nov 2023 12:13:41 +0530 Subject: [PATCH 2/5] Fixed warning --- pallets/thea-executor/src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pallets/thea-executor/src/lib.rs b/pallets/thea-executor/src/lib.rs index 44067d242..0f654c206 100644 --- a/pallets/thea-executor/src/lib.rs +++ b/pallets/thea-executor/src/lib.rs @@ -49,11 +49,7 @@ pub mod pallet { use frame_support::{ pallet_prelude::*, sp_runtime::SaturatedConversion, - traits::{ - fungible::Mutate, - fungibles::{Inspect, Mutate as OtherMutate}, - tokens::Preservation, - }, + traits::{fungible::Mutate, fungibles::Inspect, tokens::Preservation}, transactional, }; use frame_system::pallet_prelude::*; From 1bda98e8e29177a20a47b6dfc681943019f83c67 Mon Sep 17 00:00:00 2001 From: zktony Date: Tue, 14 Nov 2023 16:12:11 +0530 Subject: [PATCH 3/5] Fixed tests --- pallets/thea-executor/src/tests.rs | 6 +++--- pallets/thea-message-handler/src/mock.rs | 4 ++++ pallets/thea/src/mock.rs | 5 +++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/pallets/thea-executor/src/tests.rs b/pallets/thea-executor/src/tests.rs index ceb7b9792..31aa00bd9 100644 --- a/pallets/thea-executor/src/tests.rs +++ b/pallets/thea-executor/src/tests.rs @@ -404,7 +404,7 @@ fn test_do_withdrawal() { let asset_id = 1u128; // Set asset balance Balances::set_balance(&sender, 1_000_000_000_000_000_000); - Assets::mint_into(asset_id, &sender, 1_000_000_000_000_000_000); + let _ = Assets::mint_into(asset_id, &sender, 1_000_000_000_000_000_000); // Set withdrawal Fee assert_ok!(TheaExecutor::set_withdrawal_fee(RuntimeOrigin::root(), 1, 100)); assert_ok!(TheaExecutor::update_asset_metadata(RuntimeOrigin::root(), asset_id, 12)); @@ -430,8 +430,8 @@ fn test_do_withdrawal_with_total_amount_consumed_returns_error() { let sender = 2u64; let asset_id = 1u128; // Set asset balance - Balances::set_balance(&sender, 1_000_000_000_000_000_000); - Assets::mint_into(asset_id, &sender, 100_300_903u128); + let _ = Balances::set_balance(&sender, 1_000_000_000_000_000_000); + assert_ok!(Assets::mint_into(asset_id, &sender, 100_300_903u128)); // Set withdrawal Fee assert_ok!(TheaExecutor::set_withdrawal_fee(RuntimeOrigin::root(), 1, 100)); assert_ok!(TheaExecutor::update_asset_metadata(RuntimeOrigin::root(), asset_id, 12)); diff --git a/pallets/thea-message-handler/src/mock.rs b/pallets/thea-message-handler/src/mock.rs index 33f6469a6..13d2ddd8a 100644 --- a/pallets/thea-message-handler/src/mock.rs +++ b/pallets/thea-message-handler/src/mock.rs @@ -27,6 +27,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, BuildStorage, Permill, }; +use polkadex_primitives::AssetId; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -201,6 +202,9 @@ impl thea_executor::Config for Test { type ParaId = ParaId; type Swap = AssetConversion; type WeightInfo = thea_executor::weights::WeightInfo; + type MultiAssetIdAdapter = AssetId; + type AssetBalanceAdapter = u128; + type ExistentialDeposit = ExistentialDeposit; } impl crate::Config for Test { diff --git a/pallets/thea/src/mock.rs b/pallets/thea/src/mock.rs index 1730f64dc..8fcd5f2d3 100644 --- a/pallets/thea/src/mock.rs +++ b/pallets/thea/src/mock.rs @@ -25,6 +25,8 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, BuildStorage, Permill, }; +use polkadex_primitives::AssetId; + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; type Balance = u128; @@ -197,6 +199,9 @@ impl thea_executor::Config for Test { type ParaId = ParaId; type WeightInfo = thea_executor::weights::WeightInfo; type Swap = AssetConversion; + type MultiAssetIdAdapter = AssetId; + type AssetBalanceAdapter = u128; + type ExistentialDeposit = ExistentialDeposit; } impl frame_system::offchain::SendTransactionTypes for Test From 036c530d8ee5b1ef216e906815af9319aac14b96 Mon Sep 17 00:00:00 2001 From: zktony Date: Tue, 14 Nov 2023 17:40:15 +0530 Subject: [PATCH 4/5] Updated deposit code --- pallets/thea-executor/src/lib.rs | 22 ++++++---------------- pallets/thea-message-handler/src/mock.rs | 2 +- pallets/thea/src/mock.rs | 2 +- primitives/polkadex/src/assets.rs | 2 +- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/pallets/thea-executor/src/lib.rs b/pallets/thea-executor/src/lib.rs index 0f654c206..71b90dfeb 100644 --- a/pallets/thea-executor/src/lib.rs +++ b/pallets/thea-executor/src/lib.rs @@ -518,30 +518,20 @@ pub mod pallet { polkadex_primitives::AssetId::Polkadex ]; let amount_out: T::AssetBalanceAdapter = T::ExistentialDeposit::get().into(); - let asset1: T::MultiAssetIdAdapter = - polkadex_primitives::AssetId::Asset(deposit.asset_id).into(); - let asset2: T::MultiAssetIdAdapter = polkadex_primitives::AssetId::Polkadex.into(); - let fee_amount: T::AssetBalanceAdapter = pallet_asset_conversion::pallet::Pallet:: - ::quote_price_tokens_for_exact_tokens(asset1.into(), asset2.into(), amount_out.into(), true) - .ok_or(Error::::CannotSwapForFees)?.into(); - let fee_amount: u128 = fee_amount.into(); - ensure!(fee_amount <= deposit_amount, Error::::AmountCannotBeZero); - Self::resolve_mint(&Self::thea_account(), deposit.asset_id.into(), fee_amount)?; - T::Swap::swap_tokens_for_exact_tokens( + Self::resolve_mint(&Self::thea_account(), deposit.asset_id.into(), deposit_amount)?; + let fee_amount = T::Swap::swap_tokens_for_exact_tokens( Self::thea_account(), path, amount_out.into(), - None, + Some(deposit_amount), recipient.clone(), false, )?; - Self::resolver_deposit( + Self::resolve_transfer( deposit.asset_id.into(), - deposit_amount.saturating_sub(fee_amount), + &Self::thea_account(), recipient, - Self::thea_account(), - 1u128, - Self::thea_account(), + deposit_amount.saturating_sub(fee_amount), )?; } else { Self::resolver_deposit( diff --git a/pallets/thea-message-handler/src/mock.rs b/pallets/thea-message-handler/src/mock.rs index 13d2ddd8a..6c15b2113 100644 --- a/pallets/thea-message-handler/src/mock.rs +++ b/pallets/thea-message-handler/src/mock.rs @@ -22,12 +22,12 @@ use frame_support::{ }; use frame_system as system; use frame_system::{EnsureRoot, EnsureSigned}; +use polkadex_primitives::AssetId; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, BuildStorage, Permill, }; -use polkadex_primitives::AssetId; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; diff --git a/pallets/thea/src/mock.rs b/pallets/thea/src/mock.rs index 8fcd5f2d3..8f5ee901f 100644 --- a/pallets/thea/src/mock.rs +++ b/pallets/thea/src/mock.rs @@ -20,12 +20,12 @@ use crate::*; use frame_support::{parameter_types, traits::AsEnsureOriginWithArg, PalletId}; use frame_system as system; use frame_system::{EnsureRoot, EnsureSigned}; +use polkadex_primitives::AssetId; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, BuildStorage, Permill, }; -use polkadex_primitives::AssetId; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; diff --git a/primitives/polkadex/src/assets.rs b/primitives/polkadex/src/assets.rs index 78a7cd83a..8b2f3efbb 100644 --- a/primitives/polkadex/src/assets.rs +++ b/primitives/polkadex/src/assets.rs @@ -131,7 +131,7 @@ pub trait Resolver< from, to, amount.saturated_into(), - Preservation::Preserve, + Preservation::Expendable, )?; } Ok(()) From 2bb54e30f1249162b49eaf1391a29ed958ab8a4d Mon Sep 17 00:00:00 2001 From: zktony Date: Wed, 15 Nov 2023 10:08:09 +0530 Subject: [PATCH 5/5] Updated comment --- pallets/thea-executor/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/thea-executor/src/lib.rs b/pallets/thea-executor/src/lib.rs index 71b90dfeb..0fd90c017 100644 --- a/pallets/thea-executor/src/lib.rs +++ b/pallets/thea-executor/src/lib.rs @@ -114,7 +114,7 @@ pub mod pallet { /// Total Withdrawals #[pallet::constant] type WithdrawalSize: Get; - /// Total Withdrawals + /// Existential Deposit #[pallet::constant] type ExistentialDeposit: Get; /// Para Id