Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: OTC fees #863

Merged
merged 18 commits into from
Jul 16, 2024
33 changes: 30 additions & 3 deletions pallets/otc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use hydradx_traits::Inspect;
use orml_traits::{GetByKey, MultiCurrency, NamedMultiReservableCurrency};
use sp_core::U256;
use sp_runtime::traits::{One, Zero};
use sp_runtime::Permill;

#[cfg(test)]
mod tests;
Expand Down Expand Up @@ -101,6 +102,14 @@ pub mod pallet {
#[pallet::constant]
type ExistentialDepositMultiplier: Get<u8>;

/// Fee
#[pallet::constant]
type Fee: Get<Permill>;

/// Fee receiver
#[pallet::constant]
type FeeReceiver: Get<Self::AccountId>;

/// Weight information for the extrinsics.
type WeightInfo: WeightInfo;
}
Expand All @@ -116,13 +125,15 @@ pub mod pallet {
who: T::AccountId,
amount_in: Balance,
amount_out: Balance,
fee: Balance,
},
/// An Order has been partially filled
PartiallyFilled {
order_id: OrderId,
who: T::AccountId,
amount_in: Balance,
amount_out: Balance,
fee: Balance,
},
/// An Order has been placed
Placed {
Expand Down Expand Up @@ -266,13 +277,16 @@ pub mod pallet {
Self::ensure_min_order_amount(order.asset_out, order.amount_out)?;
Self::ensure_min_order_amount(order.asset_in, order.amount_in)?;

Self::execute_order(order, &who, amount_in, amount_out)?;
let fee = Self::calculate_fee(order.amount_out);

Self::execute_order(order, &who, amount_in, amount_out, fee)?;

Self::deposit_event(Event::PartiallyFilled {
order_id,
who,
amount_in,
amount_out,
fee,
});
Ok(())
})
Expand All @@ -291,14 +305,17 @@ pub mod pallet {
let who = ensure_signed(origin)?;
let order = <Orders<T>>::get(order_id).ok_or(Error::<T>::OrderNotFound)?;

Self::execute_order(&order, &who, order.amount_in, order.amount_out)?;
let fee = Self::calculate_fee(order.amount_out);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not to have the fee calculation inside the execute_order ? you would not need extra parameter and there would be only one place to calculate it.

i get you need to have the fee amount in the event, but the execute order can return the amount.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially it was there, but I didn't like returning fee from execute_order(). It doesn't make a lot of sense. But I can change it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or you can move the deposit event into execute order as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good, thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the latest version, we need fee in some check prior calling execute_order, so I will leave it as it is


Self::execute_order(&order, &who, order.amount_in, order.amount_out, fee)?;
<Orders<T>>::remove(order_id);

Self::deposit_event(Event::Filled {
order_id,
who,
amount_in: order.amount_in,
amount_out: order.amount_out,
fee,
});
Ok(())
}
Expand Down Expand Up @@ -352,13 +369,23 @@ impl<T: Config> Pallet<T> {
who: &T::AccountId,
amount_in: Balance,
amount_out: Balance,
fee: Balance
) -> DispatchResult {
T::Currency::transfer(order.asset_in, who, &order.owner, amount_in)?;
let remaining_to_unreserve =
// returns any amount that was unable to be unreserved
T::Currency::unreserve_named(&NAMED_RESERVE_ID, order.asset_out, &order.owner, amount_out);
ensure!(remaining_to_unreserve.is_zero(), Error::<T>::InsufficientReservedAmount);
T::Currency::transfer(order.asset_out, &order.owner, who, amount_out)?;

let amount_out_without_fee = amount_out.checked_sub(fee).ok_or(Error::<T>::MathError)?;

T::Currency::transfer(order.asset_out, &order.owner, who, amount_out_without_fee)?;
T::Currency::transfer(order.asset_out, &order.owner, &T::FeeReceiver::get(), fee)?;

Ok(())
}

fn calculate_fee(amount: Balance) -> Balance {
T::Fee::get().mul_ceil(amount)
}
}
11 changes: 8 additions & 3 deletions pallets/otc/src/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use crate as otc;
use crate::Config;
use frame_support::{
parameter_types,
parameter_types, PalletId,
traits::{Everything, Nothing},
};
use frame_system as system;
Expand All @@ -25,8 +25,8 @@ use orml_tokens::AccountData;
use orml_traits::parameter_type_with_key;
use sp_core::H256;
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
traits::{BlakeTwo256, IdentityLookup, AccountIdConversion},
BuildStorage, Permill,
};
use std::{cell::RefCell, collections::HashMap};

Expand Down Expand Up @@ -66,6 +66,9 @@ thread_local! {
parameter_types! {
pub NativeCurrencyId: AssetId = HDX;
pub ExistentialDepositMultiplier: u8 = 5;
pub OtcFee: Permill = Permill::zero(); // Permill::from_rational(1u32, 1_000_u32); // 0.1%
pub const TreasuryPalletId: PalletId = PalletId(*b"aca/trsy");
pub TreasuryAccount: AccountId = TreasuryPalletId::get().into_account_truncating();
}

parameter_type_with_key! {
Expand All @@ -81,6 +84,8 @@ impl otc::Config for Test {
type RuntimeEvent = RuntimeEvent;
type ExistentialDeposits = ExistentialDeposits;
type ExistentialDepositMultiplier = ExistentialDepositMultiplier;
type Fee = OtcFee;
type FeeReceiver = TreasuryAccount;
type WeightInfo = ();
}

Expand Down
3 changes: 3 additions & 0 deletions runtime/hydradx/src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,7 @@ parameter_types! {
pub const ExistentialDepositMultiplier: u8 = 5;
pub const PricePrecision: FixedU128 = FixedU128::from_rational(1, 100);
pub MinProfitPercentage: Perbill = Perbill::from_rational(1u32, 100_000_u32); // 0.001%
pub OtcFee: Permill = Permill::from_rational(1u32, 1_000_u32); // 0.1%
}

impl pallet_otc::Config for Runtime {
Expand All @@ -1123,6 +1124,8 @@ impl pallet_otc::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type ExistentialDeposits = AssetRegistry;
type ExistentialDepositMultiplier = ExistentialDepositMultiplier;
type Fee = OtcFee;
type FeeReceiver = TreasuryAccount;
type WeightInfo = weights::pallet_otc::HydraWeight<Runtime>;
}

Expand Down