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/order book add fulfill order partially #1559

Merged
merged 12 commits into from
Sep 21, 2023
Merged
7 changes: 7 additions & 0 deletions pallets/order-book/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ benchmarks! {

}:fill_order_full(RawOrigin::Signed(account_1.clone()), order_id)

fill_order_partial {
let (account_0, account_1, asset_0, asset_1) = set_up_users_currencies::<T>()?;

let order_id = Pallet::<T>::place_order(account_0.clone(), asset_0, asset_1, 100 * CURRENCY_0, T::SellRatio::saturating_from_integer(2).into(), 10 * CURRENCY_0)?;

}:fill_order_partial(RawOrigin::Signed(account_1.clone()), order_id, 40 * CURRENCY_0)

add_trading_pair {
let asset_0 = CurrencyId::ForeignAsset(1);
let asset_1 = CurrencyId::ForeignAsset(2);
Expand Down
147 changes: 103 additions & 44 deletions pallets/order-book/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub mod pallet {
use frame_system::pallet_prelude::{OriginFor, *};
use orml_traits::asset_registry::{self, Inspect as _};
use scale_info::TypeInfo;
use sp_arithmetic::traits::BaseArithmetic;
use sp_arithmetic::traits::{BaseArithmetic, CheckedSub};
use sp_runtime::{
traits::{
AtLeast32BitUnsigned, EnsureAdd, EnsureDiv, EnsureFixedPointNumber, EnsureMul,
Expand Down Expand Up @@ -353,6 +353,8 @@ pub mod pallet {
/// Error when unable to convert fee balance to asset balance when asset
/// out matches fee currency
BalanceConversionErr,
/// Error when the provided partial buy amount is too large.
BuyAmountTooLarge,
}

#[pallet::call]
Expand Down Expand Up @@ -459,50 +461,9 @@ pub mod pallet {
pub fn fill_order_full(origin: OriginFor<T>, order_id: T::OrderIdNonce) -> DispatchResult {
let account_id = ensure_signed(origin)?;
let order = <Orders<T>>::get(order_id)?;
let buy_amount = order.buy_amount;

ensure!(
T::TradeableAsset::can_hold(order.asset_in_id, &account_id, order.buy_amount),
Error::<T>::InsufficientAssetFunds,
);

Self::unreserve_order(&order)?;
T::TradeableAsset::transfer(
order.asset_in_id,
&account_id,
&order.placing_account,
order.buy_amount,
false,
)?;
T::TradeableAsset::transfer(
order.asset_out_id,
&order.placing_account,
&account_id,
order.max_sell_amount,
false,
)?;
Self::remove_order(order.order_id)?;

T::FulfilledOrderHook::notify_status_change(
order_id,
Swap {
amount: order.buy_amount,
currency_in: order.asset_in_id,
currency_out: order.asset_out_id,
},
)?;

Self::deposit_event(Event::OrderFulfillment {
order_id,
placing_account: order.placing_account,
fulfilling_account: account_id,
partial_fulfillment: false,
currency_in: order.asset_in_id,
currency_out: order.asset_out_id,
fulfillment_amount: order.buy_amount,
sell_rate_limit: order.max_sell_rate,
});

Ok(())
Self::fulfill_order_with_amount(order, buy_amount, account_id)
}

/// Adds a valid trading pair.
Expand Down Expand Up @@ -582,9 +543,107 @@ pub mod pallet {

Ok(())
}

/// Fill an existing order, based on the provided partial buy amount.
#[pallet::call_index(7)]
#[pallet::weight(T::Weights::fill_order_partial())]
pub fn fill_order_partial(
origin: OriginFor<T>,
order_id: T::OrderIdNonce,
buy_amount: T::Balance,
) -> DispatchResult {
cdamian marked this conversation as resolved.
Show resolved Hide resolved
let account_id = ensure_signed(origin)?;
let order = <Orders<T>>::get(order_id)?;

Self::fulfill_order_with_amount(order, buy_amount, account_id)
}
}

impl<T: Config> Pallet<T> {
pub fn fulfill_order_with_amount(
order: OrderOf<T>,
buy_amount: T::Balance,
account_id: T::AccountId,
) -> DispatchResult {
ensure!(
buy_amount >= order.min_fulfillment_amount,
Error::<T>::InsufficientOrderSize,
);

ensure!(
T::TradeableAsset::can_hold(order.asset_in_id, &account_id, buy_amount),
Error::<T>::InsufficientAssetFunds,
);

let sell_amount = Self::convert_with_ratio(
order.asset_in_id,
order.asset_out_id,
order.max_sell_rate,
buy_amount,
)?;
let remaining_buy_amount = order
.buy_amount
.checked_sub(&buy_amount)
.ok_or(Error::<T>::BuyAmountTooLarge)?;
let partial_fulfillment = !remaining_buy_amount.is_zero();

if partial_fulfillment {
Self::update_order(
cdamian marked this conversation as resolved.
Show resolved Hide resolved
order.placing_account.clone(),
order.order_id,
remaining_buy_amount,
order.max_sell_rate,
remaining_buy_amount.min(order.min_fulfillment_amount),
cdamian marked this conversation as resolved.
Show resolved Hide resolved
)?;
} else {
T::TradeableAsset::release(
order.asset_out_id,
&order.placing_account,
sell_amount,
false,
)?;

Self::remove_order(order.order_id)?;
}

T::TradeableAsset::transfer(
order.asset_in_id,
&account_id,
&order.placing_account,
buy_amount,
false,
)?;
T::TradeableAsset::transfer(
order.asset_out_id,
&order.placing_account,
&account_id,
sell_amount,
false,
)?;

T::FulfilledOrderHook::notify_status_change(
order.order_id,
Swap {
amount: buy_amount,
currency_in: order.asset_in_id,
currency_out: order.asset_out_id,
},
)?;

Self::deposit_event(Event::OrderFulfillment {
order_id: order.order_id,
placing_account: order.placing_account,
fulfilling_account: account_id,
partial_fulfillment,
currency_in: order.asset_in_id,
currency_out: order.asset_out_id,
fulfillment_amount: buy_amount,
sell_rate_limit: order.max_sell_rate,
});

Ok(())
}

/// Remove an order from storage
pub fn remove_order(order_id: T::OrderIdNonce) -> DispatchResult {
let order = <Orders<T>>::get(order_id)?;
Expand Down
1 change: 0 additions & 1 deletion pallets/order-book/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ impl orml_tokens::Config for Runtime {
}

parameter_types! {

pub const NativeToken: CurrencyId = CurrencyId::Native;
}

Expand Down
Loading
Loading