diff --git a/algebra-core/src/lib.rs b/algebra-core/src/lib.rs
index 544030bd6..62f54080d 100644
--- a/algebra-core/src/lib.rs
+++ b/algebra-core/src/lib.rs
@@ -1 +1,2 @@
 pub mod monoid;
+pub mod semigroup;
diff --git a/algebra-core/src/monoid.rs b/algebra-core/src/monoid.rs
index 63d8addc6..c3b9c421c 100644
--- a/algebra-core/src/monoid.rs
+++ b/algebra-core/src/monoid.rs
@@ -1,13 +1,17 @@
-pub trait Monoid {
+use crate::semigroup::Semigroup;
+
+pub trait Monoid: Semigroup {
     fn empty() -> Self;
-    fn combine(self, other: Self) -> Self;
+}
+
+impl Semigroup for u64 {
+    fn combine(self, other: Self) -> Self {
+        self + other
+    }
 }
 
 impl Monoid for u64 {
     fn empty() -> Self {
         0
     }
-    fn combine(self, other: Self) -> Self {
-        self + other
-    }
 }
diff --git a/algebra-core/src/semigroup.rs b/algebra-core/src/semigroup.rs
new file mode 100644
index 000000000..4de0ceb5b
--- /dev/null
+++ b/algebra-core/src/semigroup.rs
@@ -0,0 +1,3 @@
+pub trait Semigroup {
+    fn combine(self, other: Self) -> Self;
+}
diff --git a/bloom-derivation/src/lib.rs b/bloom-derivation/src/lib.rs
index cb0c102a5..3e4441893 100644
--- a/bloom-derivation/src/lib.rs
+++ b/bloom-derivation/src/lib.rs
@@ -14,6 +14,7 @@ pub fn derive_fragment(input: TokenStream) -> TokenStream {
             type U;
             fn side(&self) -> bloom_offchain::execution_engine::liquidity_book::side::SideM;
             fn input(&self) -> bloom_offchain::execution_engine::liquidity_book::types::InputAsset<u64>;
+            fn output(&self) -> bloom_offchain::execution_engine::liquidity_book::types::OutputAsset<u64>;
             fn price(&self) -> bloom_offchain::execution_engine::liquidity_book::types::AbsolutePrice;
             fn linear_fee(&self, input_consumed: bloom_offchain::execution_engine::liquidity_book::types::InputAsset<u64>) -> bloom_offchain::execution_engine::liquidity_book::types::FeeAsset<u64>;
             fn fee(&self) -> bloom_offchain::execution_engine::liquidity_book::types::FeeAsset<u64>;
diff --git a/bloom-offchain-cardano/src/orders/limit.rs b/bloom-offchain-cardano/src/orders/limit.rs
index 3c383fb65..f46073ee6 100644
--- a/bloom-offchain-cardano/src/orders/limit.rs
+++ b/bloom-offchain-cardano/src/orders/limit.rs
@@ -7,7 +7,7 @@ use cml_crypto::{blake2b224, Ed25519KeyHash, RawBytesEncoding};
 use cml_multi_era::babbage::BabbageTransactionOutput;
 
 use bloom_offchain::execution_engine::liquidity_book::fragment::{Fragment, OrderState, StateTrans};
-use bloom_offchain::execution_engine::liquidity_book::linear_output_rel;
+use bloom_offchain::execution_engine::liquidity_book::linear_output_relative;
 use bloom_offchain::execution_engine::liquidity_book::side::SideM;
 use bloom_offchain::execution_engine::liquidity_book::time::TimeBounds;
 use bloom_offchain::execution_engine::liquidity_book::types::{
@@ -148,6 +148,10 @@ impl Fragment for LimitOrder {
         self.input_amount
     }
 
+    fn output(&self) -> OutputAsset<u64> {
+        self.output_amount
+    }
+
     fn price(&self) -> AbsolutePrice {
         AbsolutePrice::from_price(self.side(), self.base_price)
     }
@@ -311,7 +315,7 @@ where
                 .checked_sub(reserved_lovelace)
                 .and_then(|lov| lov.checked_sub(conf.fee))
                 .and_then(|lov| lov.checked_sub(tradable_lovelace))?;
-            if let Some(base_output) = linear_output_rel(conf.tradable_input, conf.base_price) {
+            if let Some(base_output) = linear_output_relative(conf.tradable_input, conf.base_price) {
                 let min_marginal_output = conf.min_marginal_output;
                 let max_execution_steps_possible = base_output.checked_div(min_marginal_output);
                 let max_execution_steps_available = execution_budget.checked_div(conf.cost_per_ex_step);
diff --git a/bloom-offchain/src/execution_engine/liquidity_book/core.rs b/bloom-offchain/src/execution_engine/liquidity_book/core.rs
new file mode 100644
index 000000000..0cefdd030
--- /dev/null
+++ b/bloom-offchain/src/execution_engine/liquidity_book/core.rs
@@ -0,0 +1,198 @@
+use std::collections::HashMap;
+
+use either::Either;
+
+use algebra_core::monoid::Monoid;
+use algebra_core::semigroup::Semigroup;
+use spectrum_offchain::data::Stable;
+
+use crate::execution_engine::liquidity_book::fragment::Fragment;
+use crate::execution_engine::liquidity_book::side::SideM;
+use crate::execution_engine::liquidity_book::types::{FeeAsset, InputAsset, OutputAsset};
+
+/// Usage of liquidity from market maker.
+/// take(P, M_1 + M_2 + ... + M_n) = take(P, M_1) |> take(_, M_2) |> ... take(_, M_n)
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub struct Make {
+    pub side: SideM,
+    pub input: InputAsset<u64>,
+    pub output: OutputAsset<u64>,
+}
+
+impl Semigroup for Make {
+    fn combine(self, other: Self) -> Self {
+        todo!("Semigroup for Make")
+    }
+}
+
+/// Taking liquidity from market.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub struct TerminalTake {
+    /// Input asset removed as a result of this transaction.
+    pub removed_input: InputAsset<u64>,
+    /// Output asset added as a result of this transaction.
+    pub added_output: OutputAsset<u64>,
+    /// Overall execution budget used.
+    pub budget_used: FeeAsset<u64>,
+    /// Execution fee charged.
+    pub fee_used: FeeAsset<u64>,
+}
+
+impl TerminalTake {
+    pub fn new() -> Self {
+        Self {
+            removed_input: 0,
+            added_output: 0,
+            budget_used: 0,
+            fee_used: 0,
+        }
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum Next<S, T> {
+    /// Successive state is available.
+    Succ(S),
+    /// Terminal state.
+    Term(T),
+}
+
+/// State transition of a take.
+#[derive(Debug, Copy, Clone)]
+pub struct Trans<Cont, Term> {
+    pub target: Cont,
+    pub result: Next<Cont, Term>,
+}
+
+impl<Cont, Term> Semigroup for Trans<Cont, Term> {
+    fn combine(self, other: Self) -> Self {
+        Self {
+            target: self.target,
+            result: other.result,
+        }
+    }
+}
+
+pub type TakerTrans<Taker> = Trans<Taker, TerminalTake>;
+
+impl<T> TakerTrans<T> {
+    pub fn added_output(&self) -> OutputAsset<u64>
+    where
+        T: Fragment,
+    {
+        let accumulated_output = match &self.result {
+            Next::Succ(next) => next.output(),
+            Next::Term(term) => term.added_output,
+        };
+        accumulated_output - self.target.output()
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct TryApply<Action, Subject> {
+    pub action: Action,
+    pub target: Subject,
+    pub result: Next<Subject, ()>,
+}
+
+impl<A, S> Semigroup for TryApply<A, S>
+where
+    A: Semigroup,
+{
+    fn combine(self, other: Self) -> Self {
+        Self {
+            action: self.action.combine(other.action),
+            target: self.target,
+            result: other.result,
+        }
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct MatchmakingAttempt<Taker: Stable, Maker: Stable, U> {
+    takes: HashMap<Taker::StableId, TakerTrans<Taker>>,
+    makes: HashMap<Maker::StableId, TryApply<Make, Maker>>,
+    execution_units_consumed: U,
+}
+
+impl<Taker: Stable, Maker: Stable, U> MatchmakingAttempt<Taker, Maker, U> {
+    pub fn empty() -> Self
+    where
+        U: Monoid,
+    {
+        Self {
+            takes: HashMap::new(),
+            makes: HashMap::new(),
+            execution_units_consumed: U::empty(),
+        }
+    }
+
+    pub fn execution_units_consumed(&self) -> U
+    where
+        U: Copy,
+    {
+        self.execution_units_consumed
+    }
+
+    pub fn is_complete(&self) -> bool {
+        self.takes.len() > 0
+    }
+
+    pub fn unsatisfied_fragments(&self) -> Vec<Taker>
+    where
+        Taker: Fragment + Copy,
+    {
+        let not_ok_terminal_takes = self.takes.iter().filter_map(|(_, apply)| {
+            let target = apply.target;
+            if apply.added_output() < target.min_marginal_output() {
+                Some(target)
+            } else {
+                None
+            }
+        });
+        not_ok_terminal_takes.collect()
+    }
+
+    pub fn add_take(&mut self, take: TakerTrans<Taker>) {
+        let sid = take.target.stable_id();
+        let take_combined = match self.takes.remove(&sid) {
+            None => take,
+            Some(existing_transition) => existing_transition.combine(take),
+        };
+        self.takes.insert(sid, take_combined);
+    }
+
+    pub fn add_make(&mut self, make: TryApply<Make, Maker>) {
+        let sid = make.target.stable_id();
+        let maker_combined = match self.makes.remove(&sid) {
+            None => make,
+            Some(existing_transition) => existing_transition.combine(make),
+        };
+        self.makes.insert(sid, maker_combined);
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct Applied<Action, Subject: Stable> {
+    pub action: Action,
+    pub target: Subject::StableId,
+    pub result: Next<Subject, ()>,
+}
+
+#[derive(Debug, Clone)]
+pub struct MatchmakingRecipe<Taker: Stable, Maker: Stable> {
+    instructions: Vec<Either<Trans<Taker, TerminalTake>, Applied<Make, Maker>>>,
+}
+
+impl<Taker, Maker> MatchmakingRecipe<Taker, Maker>
+where
+    Taker: Stable,
+    Maker: Stable,
+{
+    pub fn try_from<U>(attempt: MatchmakingAttempt<Taker, Maker, U>) -> Result<Self, Option<Vec<Taker>>>
+    where
+        Taker: Fragment + Copy,
+    {
+        Err(None)
+    }
+}
diff --git a/bloom-offchain/src/execution_engine/liquidity_book/fragment.rs b/bloom-offchain/src/execution_engine/liquidity_book/fragment.rs
index a1080437a..f033110c8 100644
--- a/bloom-offchain/src/execution_engine/liquidity_book/fragment.rs
+++ b/bloom-offchain/src/execution_engine/liquidity_book/fragment.rs
@@ -1,3 +1,4 @@
+use crate::execution_engine::liquidity_book::core::{TerminalTake, Trans};
 use num_rational::Ratio;
 use std::fmt::{Display, Formatter};
 
@@ -17,6 +18,16 @@ pub trait OrderState: Sized {
     ) -> (StateTrans<Self>, ExBudgetUsed, ExFeeUsed);
 }
 
+/// Order as a state machine.
+pub trait TakerBehaviour: Sized {
+    fn with_updated_time(self, time: u64) -> Trans<Self, TerminalTake>;
+    fn with_applied_trade(
+        self,
+        removed_input: InputAsset<u64>,
+        added_output: OutputAsset<u64>,
+    ) -> Trans<Self, TerminalTake>;
+}
+
 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
 pub enum StateTrans<T> {
     /// Next state is available.
@@ -53,8 +64,10 @@ pub trait Fragment {
     type U;
     /// Side of the fragment relative to pair it maps to.
     fn side(&self) -> SideM;
-    /// Input asset.
+    /// Amount of input asset remaining.
     fn input(&self) -> InputAsset<u64>;
+    /// Amount of output asset accumulated.
+    fn output(&self) -> OutputAsset<u64>;
     /// Price of base asset in quote asset.
     fn price(&self) -> AbsolutePrice;
     /// Batcher fee for whole swap.
diff --git a/bloom-offchain/src/execution_engine/liquidity_book/pool.rs b/bloom-offchain/src/execution_engine/liquidity_book/market_maker.rs
similarity index 67%
rename from bloom-offchain/src/execution_engine/liquidity_book/pool.rs
rename to bloom-offchain/src/execution_engine/liquidity_book/market_maker.rs
index 042a06845..0c11a574a 100644
--- a/bloom-offchain/src/execution_engine/liquidity_book/pool.rs
+++ b/bloom-offchain/src/execution_engine/liquidity_book/market_maker.rs
@@ -1,25 +1,27 @@
+use crate::execution_engine::liquidity_book::core::{Make, TryApply};
 use crate::execution_engine::liquidity_book::side::Side;
 use crate::execution_engine::liquidity_book::types::AbsolutePrice;
 use derive_more::{Display, Div, From, Into, Mul};
 use num_rational::Ratio;
 use std::cmp::Ordering;
+use bignumber::BigNumber;
 
 /// Price of a theoretical 0-swap in pool.
 #[repr(transparent)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Div, Mul, From, Into, Display)]
-pub struct StaticPrice(AbsolutePrice);
+pub struct SpotPrice(AbsolutePrice);
 
-impl StaticPrice {
+impl SpotPrice {
     pub fn unwrap(self) -> Ratio<u128> {
         self.0.unwrap()
     }
 }
 
 /// Pooled liquidity.
-pub trait Pool {
+pub trait MarketMaker {
     type U;
     /// Static price (regardless swap vol) in this pool.
-    fn static_price(&self) -> StaticPrice;
+    fn static_price(&self) -> SpotPrice;
     /// Real price of swap.
     fn real_price(&self, input: Side<u64>) -> AbsolutePrice;
     /// Output of a swap.
@@ -28,9 +30,16 @@ pub trait Pool {
     fn quality(&self) -> PoolQuality;
     /// How much (approximately) execution of this fragment will cost.
     fn marginal_cost_hint(&self) -> Self::U;
-    // Determine is swaps allowed for current pool, based on lq_bound.
-    // Used for correct support of legacy v1/v2 and fee switch pools
-    fn swaps_allowed(&self) -> bool;
+    // Is this maker active at the moment or not.
+    fn is_active(&self) -> bool;
+    fn available_liquidity_by_user_impact(&self, max_user_price_impact: Side<Ratio<u64>>) -> (u64, u64);
+    fn available_liquidity_by_spot_impact(&self, max_spot_price_impact: Side<Ratio<u64>>) -> (u64, u64);
+}
+
+/// Pooled liquidity.
+pub trait MakerBehavior: Sized {
+    /// Output of a swap.
+    fn swap(self, input: Side<u64>) -> TryApply<Make, Self>;
 }
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Into, From, Display)]
diff --git a/bloom-offchain/src/execution_engine/liquidity_book/mod.rs b/bloom-offchain/src/execution_engine/liquidity_book/mod.rs
index 81bef940e..ece41f8c9 100644
--- a/bloom-offchain/src/execution_engine/liquidity_book/mod.rs
+++ b/bloom-offchain/src/execution_engine/liquidity_book/mod.rs
@@ -12,9 +12,9 @@ use spectrum_offchain::data::{Has, Stable};
 use spectrum_offchain::maker::Maker;
 
 use crate::execution_engine::liquidity_book::fragment::{Fragment, OrderState, StateTrans};
-use crate::execution_engine::liquidity_book::pool::{Pool, StaticPrice};
+use crate::execution_engine::liquidity_book::market_maker::{MarketMaker, SpotPrice};
 use crate::execution_engine::liquidity_book::recipe::{
-    ExecutionRecipe, Fill, IntermediateRecipe, PartialFill, Swap, TerminalInstruction,
+    ExecutionRecipe, Fill, IntermediateRecipe, PartialFill, Take, TerminalInstruction,
 };
 use crate::execution_engine::liquidity_book::side::Side::{Ask, Bid};
 use crate::execution_engine::liquidity_book::side::{Side, SideM};
@@ -23,9 +23,11 @@ use crate::execution_engine::liquidity_book::state::{IdleState, TLBState};
 use crate::execution_engine::liquidity_book::types::{AbsolutePrice, RelativePrice};
 use crate::execution_engine::types::Time;
 
+mod core;
 pub mod fragment;
 pub mod interpreter;
-pub mod pool;
+pub mod market_maker;
+mod parallel;
 pub mod recipe;
 pub mod side;
 pub mod stashing_option;
@@ -103,7 +105,7 @@ impl<Fr, Pl: Stable, U> TLB<Fr, Pl, U> {
 impl<Fr, Pl, U> TLB<Fr, Pl, U>
 where
     Fr: Fragment<U = U> + OrderState + Ord + Copy + Debug,
-    Pl: Pool + Stable + Copy,
+    Pl: MarketMaker + Stable + Copy,
     U: PartialOrd,
 {
     fn on_transition(&mut self, tx: StateTrans<Fr>) {
@@ -116,7 +118,7 @@ where
 impl<Fr, Pl, U> TemporalLiquidityBook<Fr, Pl> for TLB<Fr, Pl, U>
 where
     Fr: Fragment<U = U> + OrderState + Copy + Ord + Display + Debug,
-    Pl: Pool<U = U> + Stable + Copy + Debug + Display,
+    Pl: MarketMaker<U = U> + Stable + Copy + Debug + Display,
     U: PartialOrd + SubAssign + Sub<Output = U> + Copy + Debug,
 {
     fn attempt(&mut self) -> Option<ExecutionRecipe<Fr, Pl>> {
@@ -264,7 +266,7 @@ where
 impl<Fr, Pl, U> ExternalTLBEvents<Fr, Pl> for TLB<Fr, Pl, U>
 where
     Fr: Fragment + OrderState + Ord + Copy + Display,
-    Pl: Pool + Stable + Copy,
+    Pl: MarketMaker + Stable + Copy,
 {
     fn advance_clocks(&mut self, new_time: u64) {
         requiring_settled_state(self, |st| st.advance_clocks(new_time))
@@ -292,7 +294,7 @@ where
 impl<Fr, Pl, U> TLBFeedback<Fr, Pl> for TLB<Fr, Pl, U>
 where
     Fr: Fragment + OrderState + Ord + Copy,
-    Pl: Pool + Stable + Copy,
+    Pl: MarketMaker + Stable + Copy,
 {
     fn on_recipe_succeeded(&mut self) {
         self.state.commit();
@@ -309,9 +311,9 @@ const MAX_BIAS_PERCENT: u128 = 3;
 //                     |
 // p: >.... P_x ......(.)...... P_index .... P_y.... >
 //           |         |           |          |
-//          ask      bias<=3%....pivot       bid
+//          ask     |bias|<=3%...pivot       bid
 /// Settle execution price for two interleaving fragments.
-fn settle_price<Fr: Fragment>(ask: &Fr, bid: &Fr, index_price: Option<StaticPrice>) -> AbsolutePrice {
+fn settle_price<Fr: Fragment>(ask: &Fr, bid: &Fr, index_price: Option<SpotPrice>) -> AbsolutePrice {
     let price_ask = ask.price();
     let price_bid = bid.price();
     let price_ask_rat = price_ask.unwrap();
@@ -441,7 +443,7 @@ where
     }
 }
 
-pub fn linear_output_rel(input: u64, price: RelativePrice) -> Option<u64> {
+pub fn linear_output_relative(input: u64, price: RelativePrice) -> Option<u64> {
     u64::try_from(U256::from(input) * U256::from(*price.numer()) / U256::from(*price.denom())).ok()
 }
 
@@ -454,13 +456,13 @@ fn linear_output_unsafe(input: u64, price: Side<AbsolutePrice>) -> u64 {
 
 struct FillFromPool<Fr, Pl> {
     term_fill: Fill<Fr>,
-    swap: Swap<Pl>,
+    swap: Take<Pl>,
 }
 
 fn fill_from_pool<Fr, Pl>(lhs: PartialFill<Fr>, pool: Pl) -> FillFromPool<Fr, Pl>
 where
     Fr: Fragment + OrderState + Copy,
-    Pl: Pool + Copy,
+    Pl: MarketMaker + Copy,
 {
     match lhs.target.side() {
         SideM::Bid => {
@@ -469,7 +471,7 @@ where
             let quote_input = bid.remaining_input;
             let (execution_amount, next_pool) = pool.swap(Side::Bid(quote_input));
             bid.accumulated_output += execution_amount;
-            let swap = Swap {
+            let swap = Take {
                 target: pool,
                 transition: next_pool,
                 side: SideM::Bid,
@@ -487,7 +489,7 @@ where
             let base_input = ask.remaining_input;
             let (execution_amount, next_pool) = pool.swap(Side::Ask(base_input));
             ask.accumulated_output += execution_amount;
-            let swap = Swap {
+            let swap = Take {
                 target: pool,
                 transition: next_pool,
                 side: SideM::Ask,
@@ -507,9 +509,9 @@ mod tests {
     use either::Either;
 
     use crate::execution_engine::liquidity_book::fragment::StateTrans;
-    use crate::execution_engine::liquidity_book::pool::Pool;
+    use crate::execution_engine::liquidity_book::market_maker::MarketMaker;
     use crate::execution_engine::liquidity_book::recipe::{
-        ExecutionRecipe, Fill, IntermediateRecipe, PartialFill, Swap, TerminalInstruction,
+        ExecutionRecipe, Fill, IntermediateRecipe, PartialFill, Take, TerminalInstruction,
     };
     use crate::execution_engine::liquidity_book::side::SideM::Bid;
     use crate::execution_engine::liquidity_book::side::{Side, SideM};
@@ -595,7 +597,7 @@ mod tests {
                     budget_used: 990000,
                     fee_used: 990,
                 }),
-                TerminalInstruction::Swap(Swap {
+                TerminalInstruction::Swap(Take {
                     target: p1,
                     transition: p2,
                     side: SideM::Ask,
diff --git a/bloom-offchain/src/execution_engine/liquidity_book/parallel.rs b/bloom-offchain/src/execution_engine/liquidity_book/parallel.rs
new file mode 100644
index 000000000..9b81ebc0b
--- /dev/null
+++ b/bloom-offchain/src/execution_engine/liquidity_book/parallel.rs
@@ -0,0 +1,181 @@
+use std::fmt::Debug;
+
+use algebra_core::monoid::Monoid;
+use spectrum_offchain::data::Stable;
+
+use crate::execution_engine::liquidity_book::core::{Make, TryApply};
+use crate::execution_engine::liquidity_book::core::{
+    MatchmakingAttempt, MatchmakingRecipe, Next, TakerTrans,
+};
+use crate::execution_engine::liquidity_book::fragment::{Fragment, OrderState, TakerBehaviour};
+use crate::execution_engine::liquidity_book::market_maker::{MakerBehavior, MarketMaker, SpotPrice};
+use crate::execution_engine::liquidity_book::side::Side::{Ask, Bid};
+use crate::execution_engine::liquidity_book::side::{Side, SideM};
+use crate::execution_engine::liquidity_book::stashing_option::StashingOption;
+use crate::execution_engine::liquidity_book::state::{max_by_distance_to_spot, max_by_volume, TLBState};
+use crate::execution_engine::liquidity_book::types::AbsolutePrice;
+use crate::execution_engine::liquidity_book::{
+    linear_output_unsafe, settle_price, ExecutionCap, TLBFeedback,
+};
+
+/// TLB is a Universal Liquidity Aggregator (ULA), it is able to aggregate every piece of composable
+/// liquidity available in the market.
+///
+/// Composable liquidity falls into two essential categories:
+/// (1.) Discrete Fragments of liquidity;
+/// (2.) Pooled (according to some AMM formula) liquidity;
+pub trait TemporalLiquidityBook<Taker: Stable, Maker: Stable> {
+    fn attempt(&mut self) -> Option<MatchmakingRecipe<Taker, Maker>>;
+}
+
+#[derive(Debug, Clone)]
+pub struct TLB<Taker, Maker: Stable, U> {
+    state: TLBState<Taker, Maker>,
+    execution_cap: ExecutionCap<U>,
+    attempt_side: SideM,
+}
+
+impl<Taker, Maker, U> TLBFeedback<Taker, Maker> for TLB<Taker, Maker, U>
+where
+    Taker: Fragment + OrderState + Ord + Copy,
+    Maker: MarketMaker + Stable + Copy,
+{
+    fn on_recipe_succeeded(&mut self) {
+        self.state.commit();
+    }
+
+    fn on_recipe_failed(&mut self, stashing_opt: StashingOption<Taker>) {
+        self.state.rollback(stashing_opt);
+    }
+}
+
+impl<Taker, Maker, U> TLB<Taker, Maker, U>
+where
+    Maker: MarketMaker + Stable,
+{
+    fn spot_price(&self) -> Option<SpotPrice> {
+        None
+    }
+}
+
+impl<Taker, Maker, U> TLB<Taker, Maker, U>
+where
+    Taker: Fragment<U = U> + Ord + Copy + Debug,
+    Maker: MarketMaker + Stable + Copy,
+    U: PartialOrd,
+{
+    fn on_take<Any>(&mut self, tx: Next<Taker, Any>) {
+        if let Next::Succ(next) = tx {
+            self.state.pre_add_fragment(next);
+        }
+    }
+
+    fn on_make<Any>(&mut self, tx: Next<Maker, Any>) {
+        if let Next::Succ(next) = tx {
+            self.state.pre_add_pool(next);
+        }
+    }
+}
+
+impl<Taker, Maker, U> TemporalLiquidityBook<Taker, Maker> for TLB<Taker, Maker, U>
+where
+    Taker: Stable + Fragment<U = U> + TakerBehaviour + Ord + Copy + Debug,
+    Maker: Stable + MarketMaker<U = U> + MakerBehavior + Copy + Debug,
+    U: Monoid + PartialOrd + Copy,
+{
+    fn attempt(&mut self) -> Option<MatchmakingRecipe<Taker, Maker>> {
+        let mut batch: MatchmakingAttempt<Taker, Maker, U> = MatchmakingAttempt::empty();
+        while batch.execution_units_consumed() < self.execution_cap.soft {
+            let spot_price = self.spot_price();
+            if let Some(target_taker) = self.state.pick_taker(|fs| {
+                spot_price
+                    .map(|sp| max_by_distance_to_spot(fs, sp))
+                    .unwrap_or(max_by_volume(fs))
+            }) {
+                let target_side = target_taker.side();
+                let target_price = target_side.wrap(target_taker.price());
+                let maybe_price_counter_taker = self.state.best_fr_price(!target_side);
+                let chunk_offered = target_side.wrap(0); // todo
+                let maybe_price_maker = self.state.preselect_market_maker(chunk_offered);
+                match (maybe_price_counter_taker, maybe_price_maker) {
+                    (Some(price_counter_taker), maybe_price_maker)
+                        if maybe_price_maker
+                            .map(|(_, p)| price_counter_taker.better_than(p))
+                            .unwrap_or(true) =>
+                    {
+                        if let Some(counter_taker) = self.state.try_pick_fr(!target_side, ok) {
+                            //fill target_taker <- counter_taker
+                            let make_match = |ask: &Taker, bid: &Taker| settle_price(ask, bid, spot_price);
+                            let (take_a, take_b) =
+                                execute_with_taker(target_taker, counter_taker, make_match);
+                            for take in vec![take_a, take_b] {
+                                batch.add_take(take);
+                                self.on_take(take.result);
+                            }
+                        }
+                    }
+                    (_, Some((maker_sid, price_maker))) if target_price.overlaps(price_maker) => {
+                        if let Some(maker) = self.state.take_pool(&maker_sid) {
+                            //fill target_taker <- maker
+                            let (take, make) = execute_with_maker(target_taker, maker, chunk_offered);
+                            batch.add_take(take);
+                            batch.add_make(make);
+                            self.on_take(take.result);
+                            self.on_make(make.result);
+                        }
+                    }
+                    _ => {}
+                }
+            }
+        }
+        None
+    }
+}
+
+fn execute_with_maker<Taker, Maker>(
+    target_taker: Taker,
+    maker: Maker,
+    chunk_size: Side<u64>,
+) -> (TakerTrans<Taker>, TryApply<Make, Maker>)
+where
+    Taker: Fragment + TakerBehaviour + Copy,
+    Maker: MakerBehavior + Copy,
+{
+    let maker_applied = maker.swap(chunk_size);
+    let taker_applied = target_taker.with_applied_trade(chunk_size.unwrap(), maker_applied.action.output);
+    (taker_applied, maker_applied)
+}
+
+fn execute_with_taker<Taker, F>(
+    target_taker: Taker,
+    counter_taker: Taker,
+    matchmaker: F,
+) -> (TakerTrans<Taker>, TakerTrans<Taker>)
+where
+    Taker: Fragment + TakerBehaviour + Copy,
+    F: FnOnce(&Taker, &Taker) -> AbsolutePrice,
+{
+    let (ask, bid) = match target_taker.side() {
+        SideM::Bid => (counter_taker, target_taker),
+        SideM::Ask => (target_taker, counter_taker),
+    };
+    let price = matchmaker(&ask, &bid);
+    let quote_input = bid.input();
+    let demand_base = linear_output_unsafe(quote_input, Bid(price));
+    let supply_base = ask.input();
+    let (quote, base) = if supply_base > demand_base {
+        (quote_input, demand_base)
+    } else if supply_base < demand_base {
+        let quote_executed = linear_output_unsafe(supply_base, Ask(price));
+        (quote_executed, supply_base)
+    } else {
+        (quote_input, demand_base)
+    };
+    let next_bid = bid.with_applied_trade(quote, base);
+    let next_ask = ask.with_applied_trade(base, quote);
+    (next_bid, next_ask)
+}
+
+fn ok<'a, T>(_: &'a T) -> bool {
+    true
+}
diff --git a/bloom-offchain/src/execution_engine/liquidity_book/recipe.rs b/bloom-offchain/src/execution_engine/liquidity_book/recipe.rs
index 8ef41bb1a..f65858845 100644
--- a/bloom-offchain/src/execution_engine/liquidity_book/recipe.rs
+++ b/bloom-offchain/src/execution_engine/liquidity_book/recipe.rs
@@ -1,4 +1,5 @@
 use std::cmp::max;
+use std::collections::HashMap;
 use std::fmt::{Debug, Display, Formatter};
 
 use log::{info, trace};
@@ -169,7 +170,7 @@ impl<Fr, Pl, Src> LinkedTerminalInstruction<Fr, Pl, Src> {
 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
 pub enum TerminalInstruction<Fr, Pl> {
     Fill(Fill<Fr>),
-    Swap(Swap<Pl>),
+    Swap(Take<Pl>),
 }
 
 impl<Fr: Display, Pl: Display> Display for TerminalInstruction<Fr, Pl> {
@@ -340,7 +341,7 @@ pub struct LinkedSwap<Pl, Src> {
 }
 
 impl<Pl, Src> LinkedSwap<Pl, Src> {
-    pub fn from_swap(swap: Swap<Pl>, target_src: Src) -> Self {
+    pub fn from_swap(swap: Take<Pl>, target_src: Src) -> Self {
         Self {
             target: Bundled(swap.target, target_src),
             transition: swap.transition,
@@ -352,7 +353,7 @@ impl<Pl, Src> LinkedSwap<Pl, Src> {
 }
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub struct Swap<Pl> {
+pub struct Take<Pl> {
     pub target: Pl,
     pub transition: Pl,
     pub side: SideM,
@@ -360,7 +361,7 @@ pub struct Swap<Pl> {
     pub output: u64,
 }
 
-impl<Pl: Display> Display for Swap<Pl> {
+impl<Pl: Display> Display for Take<Pl> {
     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
         f.write_str(&*format!(
             "Swap(target={}, transition={}, side={}, input={}, output={})",
diff --git a/bloom-offchain/src/execution_engine/liquidity_book/state.rs b/bloom-offchain/src/execution_engine/liquidity_book/state.rs
index 658089671..880debb9b 100644
--- a/bloom-offchain/src/execution_engine/liquidity_book/state.rs
+++ b/bloom-offchain/src/execution_engine/liquidity_book/state.rs
@@ -1,4 +1,3 @@
-use either::{Either, Left, Right};
 use std::collections::hash_map::Entry;
 use std::collections::{btree_map, BTreeMap, BTreeSet, HashMap, HashSet};
 use std::fmt::{Debug, Display, Formatter};
@@ -6,15 +5,16 @@ use std::hash::Hash;
 use std::mem;
 use std::ops::Add;
 
+use either::{Either, Left, Right};
 use log::trace;
 
 use spectrum_offchain::data::Stable;
 
 use crate::execution_engine::liquidity_book::fragment::{Fragment, OrderState, StateTrans};
-use crate::execution_engine::liquidity_book::pool::{Pool, PoolQuality, StaticPrice};
+use crate::execution_engine::liquidity_book::market_maker::{MarketMaker, PoolQuality, SpotPrice};
 use crate::execution_engine::liquidity_book::side::{Side, SideM};
 use crate::execution_engine::liquidity_book::stashing_option::StashingOption;
-use crate::execution_engine::liquidity_book::types::AbsolutePrice;
+use crate::execution_engine::liquidity_book::types::{AbsolutePrice, InputAsset};
 use crate::execution_engine::liquidity_book::weight::Weighted;
 
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -36,7 +36,7 @@ impl<Fr, Pl: Stable> IdleState<Fr, Pl> {
 impl<Fr, Pl> IdleState<Fr, Pl>
 where
     Fr: Fragment + OrderState + Ord + Copy,
-    Pl: Pool + Stable + Copy,
+    Pl: MarketMaker + Stable + Copy,
 {
     pub fn advance_clocks(&mut self, new_time: u64) {
         self.fragments.advance_clocks(new_time)
@@ -417,12 +417,27 @@ where
     }
 }
 
+pub fn max_by_distance_to_spot<Fr>(fragments: &mut Fragments<Fr>, spot_price: SpotPrice) -> Option<Fr> {
+    None
+}
+
+pub fn max_by_volume<Fr>(fragments: &mut Fragments<Fr>) -> Option<Fr> {
+    None
+}
+
 impl<Fr, Pl, U> TLBState<Fr, Pl>
 where
     Fr: Fragment<U = U> + Ord + Copy + Debug,
-    Pl: Pool + Stable + Copy,
+    Pl: MarketMaker + Stable + Copy,
     U: PartialOrd,
 {
+    pub fn pick_taker<F>(&mut self, strategy: F) -> Option<Fr>
+    where
+        F: FnOnce(&mut Fragments<Fr>) -> Option<Fr>,
+    {
+        None
+    }
+
     pub fn show_state(&self) -> String
     where
         Pl::StableId: Display,
@@ -551,17 +566,35 @@ where
 impl<Fr, Pl> TLBState<Fr, Pl>
 where
     Fr: Fragment + Ord + Copy,
-    Pl: Pool + Stable + Copy,
+    Pl: MarketMaker + Stable + Copy,
 {
-    pub fn try_select_pool(
+    pub fn best_market_maker(&self) -> Option<&Pl> {
+        self.pools().pools.values().max_by_key(|p| p.quality())
+    }
+
+    pub fn preselect_market_maker(
         &self,
-        trade_hint: Side<u64>,
-    ) -> Option<(AbsolutePrice, StaticPrice, Pl::StableId)> {
+        offered_amount: Side<InputAsset<u64>>,
+    ) -> Option<(Pl::StableId, AbsolutePrice)> {
         let pools = self
             .pools()
             .pools
             .values()
-            .filter(|pool| pool.swaps_allowed())
+            .filter(|pool| pool.is_active())
+            .map(|p| (p.stable_id(), p.real_price(offered_amount)))
+            .collect::<Vec<_>>();
+        match offered_amount {
+            Side::Bid(_) => pools.into_iter().min_by_key(|(_, rp)| *rp),
+            Side::Ask(_) => pools.into_iter().max_by_key(|(_, rp)| *rp),
+        }
+    }
+
+    pub fn try_select_pool(&self, trade_hint: Side<u64>) -> Option<(AbsolutePrice, SpotPrice, Pl::StableId)> {
+        let pools = self
+            .pools()
+            .pools
+            .values()
+            .filter(|pool| pool.is_active())
             .map(|p| {
                 let real_p = p.real_price(trade_hint);
                 let static_p = p.static_price();
@@ -910,7 +943,7 @@ impl<Pl: Stable> Pools<Pl> {
 
 impl<Pl> Pools<Pl>
 where
-    Pl: Pool + Stable + Copy,
+    Pl: MarketMaker + Stable + Copy,
 {
     pub fn update_pool(&mut self, pool: Pl) {
         if let Some(old_pool) = self.pools.insert(pool.stable_id(), pool) {
@@ -928,18 +961,17 @@ where
 
 #[cfg(test)]
 pub mod tests {
-    use either::Left;
     use std::cmp::Ordering;
     use std::fmt::{Debug, Display, Formatter};
 
+    use either::Left;
+
     use spectrum_offchain::data::Stable;
 
     use crate::execution_engine::liquidity_book::fragment::{Fragment, OrderState, StateTrans};
-    use crate::execution_engine::liquidity_book::pool::{Pool, StaticPrice};
+    use crate::execution_engine::liquidity_book::market_maker::{MarketMaker, SpotPrice};
     use crate::execution_engine::liquidity_book::side::{Side, SideM};
-    use crate::execution_engine::liquidity_book::state::{
-        Fragments, IdleState, PoolQuality, StashingOption, TLBState,
-    };
+    use crate::execution_engine::liquidity_book::state::{IdleState, PoolQuality, StashingOption, TLBState};
     use crate::execution_engine::liquidity_book::time::TimeBounds;
     use crate::execution_engine::liquidity_book::types::{
         AbsolutePrice, ExBudgetUsed, ExCostUnits, ExFeeUsed, OutputAsset,
@@ -1330,7 +1362,7 @@ pub mod tests {
             }
         }
 
-        fn with_applied_swap(
+        fn apply_swap(
             mut self,
             removed_input: u64,
             added_output: u64,
@@ -1377,10 +1409,10 @@ pub mod tests {
         }
     }
 
-    impl Pool for SimpleCFMMPool {
+    impl MarketMaker for SimpleCFMMPool {
         type U = u64;
 
-        fn static_price(&self) -> StaticPrice {
+        fn static_price(&self) -> SpotPrice {
             AbsolutePrice::new(self.reserves_quote, self.reserves_base).into()
         }
 
@@ -1430,7 +1462,7 @@ pub mod tests {
             10
         }
 
-        fn swaps_allowed(&self) -> bool {
+        fn is_active(&self) -> bool {
             // SimpleCFMMPool used only for tests
             true
         }
diff --git a/spectrum-cardano-lib/src/ex_units.rs b/spectrum-cardano-lib/src/ex_units.rs
index 2640aaba3..60e4d5c1f 100644
--- a/spectrum-cardano-lib/src/ex_units.rs
+++ b/spectrum-cardano-lib/src/ex_units.rs
@@ -1,4 +1,5 @@
 use algebra_core::monoid::Monoid;
+use algebra_core::semigroup::Semigroup;
 use derive_more::{Add, AddAssign, Sub, SubAssign};
 use std::ops::Add;
 
@@ -19,13 +20,16 @@ impl ExUnits {
     }
 }
 
+impl Semigroup for ExUnits {
+    fn combine(self, other: Self) -> Self {
+        self.add(other)
+    }
+}
+
 impl Monoid for ExUnits {
     fn empty() -> Self {
         ExUnits { mem: 0, steps: 0 }
     }
-    fn combine(self, other: Self) -> Self {
-        self.add(other)
-    }
 }
 
 impl From<ExUnits> for cml_chain::plutus::ExUnits {
diff --git a/spectrum-offchain-cardano/Cargo.toml b/spectrum-offchain-cardano/Cargo.toml
index b8db88501..cd2e8916a 100644
--- a/spectrum-offchain-cardano/Cargo.toml
+++ b/spectrum-offchain-cardano/Cargo.toml
@@ -26,6 +26,8 @@ futures = "0.3.25"
 tokio = { version = "1.22.0", features = ["full"] }
 log = "0.4.17"
 log4rs = "1.2.0"
+dashu-base = "0.4.1"
+dashu-float = "0.4.1"
 rand = { version = "0.8.5", features = ["small_rng"] }
 rand_chacha = "0.3.1"
 async-trait = "0.1.58"
diff --git a/spectrum-offchain-cardano/src/data/balance_pool.rs b/spectrum-offchain-cardano/src/data/balance_pool.rs
index 55a8d4a85..ed04ff301 100644
--- a/spectrum-offchain-cardano/src/data/balance_pool.rs
+++ b/spectrum-offchain-cardano/src/data/balance_pool.rs
@@ -1,32 +1,35 @@
 use std::fmt::Debug;
-use std::ops::Mul;
+use std::ops::{Div, Mul, Neg};
 
 use bignumber::BigNumber;
 use cml_chain::address::Address;
 use cml_chain::assets::MultiAsset;
 use cml_chain::certs::StakeCredential;
-use cml_chain::plutus::utils::ConstrPlutusDataEncoding;
 use cml_chain::plutus::{ConstrPlutusData, PlutusData};
+use cml_chain::plutus::utils::ConstrPlutusDataEncoding;
 use cml_chain::transaction::{ConwayFormatTxOut, DatumOption, TransactionOutput};
 use cml_chain::utils::BigInteger;
 use cml_chain::Value;
 use cml_core::serialization::LenEncoding::{Canonical, Indefinite};
 use cml_multi_era::babbage::BabbageTransactionOutput;
+use dashu_base::sign::Abs;
+use dashu_float::DBig;
 use num_integer::Roots;
 use num_rational::Ratio;
 use num_traits::{CheckedAdd, CheckedSub};
+use num_traits::ToPrimitive;
 use primitive_types::U512;
 
-use bloom_offchain::execution_engine::liquidity_book::pool::{Pool, PoolQuality, StaticPrice};
+use bloom_offchain::execution_engine::liquidity_book::market_maker::{MarketMaker, PoolQuality, SpotPrice};
 use bloom_offchain::execution_engine::liquidity_book::side::{Side, SideM};
 use bloom_offchain::execution_engine::liquidity_book::types::AbsolutePrice;
+use spectrum_cardano_lib::{TaggedAmount, TaggedAssetClass};
 use spectrum_cardano_lib::ex_units::ExUnits;
 use spectrum_cardano_lib::plutus_data::{ConstrPlutusDataExtension, DatumExtension};
 use spectrum_cardano_lib::plutus_data::{IntoPlutusData, PlutusDataExtension};
 use spectrum_cardano_lib::transaction::TransactionOutputExtension;
 use spectrum_cardano_lib::types::TryFromPData;
 use spectrum_cardano_lib::value::ValueExtension;
-use spectrum_cardano_lib::{TaggedAmount, TaggedAssetClass};
 use spectrum_offchain::data::{Has, Stable};
 use spectrum_offchain::ledger::{IntoLedger, TryFromLedger};
 
@@ -39,10 +42,10 @@ use crate::data::pair::order_canonical;
 use crate::data::pool::{
     ApplyOrder, ApplyOrderError, AssetDeltas, CFMMPoolAction, ImmutablePoolUtxo, Lq, PoolBounds, Rx, Ry,
 };
-use crate::data::redeem::ClassicalOnChainRedeem;
 use crate::data::PoolId;
-use crate::deployment::ProtocolValidator::BalanceFnPoolV1;
+use crate::data::redeem::ClassicalOnChainRedeem;
 use crate::deployment::{DeployedScriptInfo, DeployedValidator, DeployedValidatorErased, RequiresValidator};
+use crate::deployment::ProtocolValidator::BalanceFnPoolV1;
 use crate::pool_math::balance_math::balance_cfmm_output_amount;
 use crate::pool_math::cfmm_math::{classic_cfmm_reward_lp, classic_cfmm_shares_amount};
 
@@ -388,9 +391,9 @@ impl AMMOps for BalancePool {
     }
 }
 
-impl Pool for BalancePool {
+impl MarketMaker for BalancePool {
     type U = ExUnits;
-    fn static_price(&self) -> StaticPrice {
+    fn static_price(&self) -> SpotPrice {
         let x = self.asset_x.untag();
         let y = self.asset_y.untag();
         let [base, _] = order_canonical(x, y);
@@ -484,13 +487,156 @@ impl Pool for BalancePool {
         self.marginal_cost
     }
 
-    fn swaps_allowed(&self) -> bool {
+    fn is_active(&self) -> bool {
         if self.asset_x.is_native() {
             self.reserves_x.untag() >= self.min_pool_lovelace
         } else {
             self.reserves_y.untag() >= self.min_pool_lovelace
         }
     }
+
+    fn available_liquidity_by_user_impact(&self, max_user_price_impact: Side<Ratio<u64>>) -> (u64, u64) {
+        // "max_user_price_impact" is calculated as
+        // "max_user_price_impact = 1 - avg_sell_price / market_price" to be always > 0.
+        // Outputs are ("quote_amount_available", "base_amount_required").
+        // Outputs reflects how many quote asset the user will receive and how many base asset
+        // must be added to the pool in order for this operation to occur with a given
+        // "max_price_impact" relative to the current state of the pool.
+        // Note: all calculations are made taking fees into account, thus "max_user_price_impact"
+        // must also include fees in "market_price" calculation.
+        const BN_ONE: BigNumber = BigNumber { value: DBig::ONE };
+
+        const MAX_ERR: i32 = 1;
+        const MAX_ITERS: u32 = 25;
+
+        let (tradable_reserves_base, w_base, tradable_reserves_quote, w_quote, total_fee_mult) =
+            match max_user_price_impact {
+                Side::Bid(_) => (
+                    BigNumber::from((self.reserves_y - self.treasury_y).untag() as f64),
+                    BigNumber::from(self.weight_y as f64).div(BigNumber::from(WEIGHT_FEE_DEN as f64)),
+                    BigNumber::from((self.reserves_x - self.treasury_x).untag() as f64),
+                    BigNumber::from(self.weight_x as f64).div(BigNumber::from(WEIGHT_FEE_DEN as f64)),
+                    BigNumber::from((self.lp_fee_y - self.treasury_fee).to_f64().unwrap()),
+                ),
+                Side::Ask(_) => (
+                    BigNumber::from((self.reserves_x - self.treasury_x).untag() as f64),
+                    BigNumber::from(self.weight_x as f64).div(BigNumber::from(WEIGHT_FEE_DEN as f64)),
+                    BigNumber::from((self.reserves_y - self.treasury_y).untag() as f64),
+                    BigNumber::from(self.weight_y as f64).div(BigNumber::from(WEIGHT_FEE_DEN as f64)),
+                    BigNumber::from((self.lp_fee_x - self.treasury_fee).to_f64().unwrap()),
+                ),
+            };
+        let lq_balance =
+            tradable_reserves_base.pow(&w_base.clone()) * tradable_reserves_quote.pow(&w_quote.clone());
+
+        let market_price = tradable_reserves_quote
+            .clone()
+            .div(w_quote.clone())
+            .div(tradable_reserves_base.clone().div(w_base.clone()))
+            * total_fee_mult.clone();
+
+        let avg_sell_price = market_price
+            * (BN_ONE
+                - BigNumber::from(*max_user_price_impact.unwrap().numer() as f64)
+                    .div(BigNumber::from(*max_user_price_impact.unwrap().denom() as f64)));
+
+        //# Constants for calculations:
+        let a = (w_base.clone() + w_quote.clone()) / w_quote.clone();
+        let b = BN_ONE - a.clone();
+        let c = lq_balance.pow(&BN_ONE.div(w_quote.clone())) * w_base.clone() / w_quote.clone();
+        let k = c.clone() / b.clone();
+        //
+        let x0 = tradable_reserves_base.clone();
+        let mut x1 = x0.clone().mul(BigNumber::from(1.1)).to_precision(0); //int(1.1 * x0);
+        let mut err = tradable_reserves_base.clone();
+        let mut counter = 0;
+        // // # Numerical calculation procedure (usual less than 5 iterations).
+        // // # You can increase 'maxErr' value to decrease number of iters.
+        while err.to_precision(10).value.ge(&DBig::from(MAX_ERR)) && counter < MAX_ITERS {
+            let f_x = (avg_sell_price.clone().div(total_fee_mult.clone()))
+                - k.clone() * (x1.clone().pow(&b.clone()) - x0.clone().pow(&b.clone()))
+                    / (x1.clone() - x0.clone());
+            let f_x_der = k.clone()
+                * ((b.clone() - BN_ONE) * x1.clone().pow(&(b.clone() + BN_ONE))
+                    + x1.clone() * x0.clone().pow(&b.clone())
+                    - b.clone() * x0.clone() * x1.clone().pow(&b.clone()))
+                / (x1.clone() * (x1.clone() - x0.clone()).powi(2));
+            let add = f_x.clone().div(f_x_der.clone());
+
+            if (x1.clone() + add.clone()).value.to_f64().value() > 0_f64 {
+                x1 = x1.clone() + add.clone();
+                err = BigNumber::from(add.clone().value.to_f32().value().abs());
+                counter += 1;
+            } else {
+                break;
+            }
+        }
+        let base_delta = (x1.clone() - tradable_reserves_base.clone()) / total_fee_mult;
+
+        let tradable_reserves_quote_final =
+            (lq_balance / x1.clone().pow(&w_base.clone())).pow(&BN_ONE.div(&w_quote));
+        let quote_delta = tradable_reserves_quote - tradable_reserves_quote_final;
+
+        return (
+            <u64>::try_from(quote_delta.value.to_int().value()).unwrap(),
+            <u64>::try_from(base_delta.value.to_int().value()).unwrap(),
+        );
+    }
+    fn available_liquidity_by_spot_impact(&self, max_spot_price_impact: Side<Ratio<u64>>) -> (u64, u64) {
+        // "max_spot_price_impact" is calculated as
+        // "max_spot_price_impact = 1 - market_price_new / market_price" to be always > 0.
+        // Outputs are ("quote_amount_available", "base_amount_required").
+        // Outputs reflects how many quote asset the user will receive and how many base asset
+        // must be added to the pool in order for this operation to occur with a given
+        // "max_spot_price_impact" relative to the current state of the pool.
+        // Note: all calculations are made taking fees into account, thus "max_spot_price_impact"
+        // must also include fees in "market_price" calculation.
+        const BN_ONE: BigNumber = BigNumber { value: DBig::ONE };
+
+        let (tradable_reserves_base, w_base, tradable_reserves_quote, w_quote, total_fee_mult) =
+            match max_spot_price_impact {
+                Side::Bid(_) => (
+                    BigNumber::from((self.reserves_y - self.treasury_y).untag() as f64),
+                    BigNumber::from(self.weight_y as f64).div(BigNumber::from(WEIGHT_FEE_DEN as f64)),
+                    BigNumber::from((self.reserves_x - self.treasury_x).untag() as f64),
+                    BigNumber::from(self.weight_x as f64).div(BigNumber::from(WEIGHT_FEE_DEN as f64)),
+                    BigNumber::from((self.lp_fee_y - self.treasury_fee).to_f64().unwrap()),
+                ),
+                Side::Ask(_) => (
+                    BigNumber::from((self.reserves_x - self.treasury_x).untag() as f64),
+                    BigNumber::from(self.weight_x as f64).div(BigNumber::from(WEIGHT_FEE_DEN as f64)),
+                    BigNumber::from((self.reserves_y - self.treasury_y).untag() as f64),
+                    BigNumber::from(self.weight_y as f64).div(BigNumber::from(WEIGHT_FEE_DEN as f64)),
+                    BigNumber::from((self.lp_fee_x - self.treasury_fee).to_f64().unwrap()),
+                ),
+            };
+        let lq_balance =
+            tradable_reserves_base.pow(&w_base.clone()) * tradable_reserves_quote.pow(&w_quote.clone());
+
+        let market_price = tradable_reserves_quote
+            .clone()
+            .div(w_quote.clone())
+            .div(tradable_reserves_base.clone().div(w_base.clone()))
+            * total_fee_mult.clone();
+
+        let impact_price = market_price.clone()
+            * (BN_ONE
+                - BigNumber::from(*max_spot_price_impact.unwrap().numer() as f64)
+                    .div(BigNumber::from(*max_spot_price_impact.unwrap().denom() as f64)));
+        //# Constants for calculations:
+        let x1 = (market_price.clone() / impact_price.clone()).pow(&w_quote.clone())
+            * tradable_reserves_base.clone();
+        let base_delta = (x1.clone() - tradable_reserves_base.clone()) / total_fee_mult;
+
+        let tradable_reserves_quote_final =
+            (lq_balance / x1.clone().pow(&w_base.clone())).pow(&BN_ONE.div(&w_quote));
+        let quote_delta = tradable_reserves_quote - tradable_reserves_quote_final;
+
+        return (
+            <u64>::try_from(quote_delta.value.to_int().value()).unwrap(),
+            <u64>::try_from(base_delta.value.to_int().value()).unwrap(),
+        );
+    }
 }
 
 impl ApplyOrder<ClassicalOnChainDeposit> for BalancePool {
@@ -602,38 +748,39 @@ impl ApplyOrder<ClassicalOnChainRedeem> for BalancePool {
 
 #[cfg(test)]
 mod tests {
-    use cml_chain::plutus::PlutusData;
     use cml_chain::Deserialize;
+    use cml_chain::plutus::PlutusData;
     use cml_core::serialization::Serialize;
     use cml_crypto::{Ed25519KeyHash, ScriptHash, TransactionHash};
     use num_rational::Ratio;
 
-    use crate::constants::MAX_LQ_CAP;
-    use bloom_offchain::execution_engine::liquidity_book::pool::Pool;
+    use bloom_offchain::execution_engine::liquidity_book::market_maker::MarketMaker;
     use bloom_offchain::execution_engine::liquidity_book::side::Side;
+    use bloom_offchain::execution_engine::liquidity_book::side::Side::{Ask, Bid};
+    use spectrum_cardano_lib::{AssetClass, AssetName, OutputRef, TaggedAmount, TaggedAssetClass};
     use spectrum_cardano_lib::ex_units::ExUnits;
     use spectrum_cardano_lib::types::TryFromPData;
-    use spectrum_cardano_lib::{AssetClass, AssetName, OutputRef, TaggedAmount, TaggedAssetClass};
 
+    use crate::data::{OnChainOrderId, PoolId};
     use crate::data::balance_pool::{BalancePool, BalancePoolConfig, BalancePoolRedeemer, BalancePoolVer};
     use crate::data::order::ClassicalOrder;
     use crate::data::order::OrderType::BalanceFn;
     use crate::data::pool::{ApplyOrder, CFMMPoolAction};
     use crate::data::redeem::{ClassicalOnChainRedeem, Redeem};
-    use crate::data::{OnChainOrderId, PoolId};
 
     const DATUM_SAMPLE: &str = "d8799fd8799f581c5df8fe3f9f0e10855f930e0ea6c227e3bba0aba54d39f9d55b95e21c436e6674ffd8799f4040ff01d8799f581c4b3459fd18a1dbabe207cd19c9951a9fac9f5c0f9c384e3d97efba26457465737443ff04d8799f581c0df79145b95580c14ef4baf8d022d7f0cbb08f3bed43bf97a2ddd8cb426c71ff1a000186820a00009fd8799fd87a9f581cb046b660db0eaf9be4f4300180ccf277e4209dada77c48fbd37ba81dffffff581c8d4be10d934b60a22f267699ea3f7ebdade1f8e535d1bd0ef7ce18b61a0501bced08ff";
 
-    #[test]
-    fn parse_balance_pool_datum() {
-        let pd = PlutusData::from_cbor_bytes(&*hex::decode(DATUM_SAMPLE).unwrap()).unwrap();
-        let maybe_conf = BalancePoolConfig::try_from_pd(pd);
-        assert!(maybe_conf.is_some())
-    }
-
-    #[test]
-    fn swap() {
-        let pool = BalancePool {
+    fn gen_ada_token_pool(
+        reserves_x: u64,
+        reserves_y: u64,
+        liquidity: u64,
+        lp_fee_x: u64,
+        lp_fee_y: u64,
+        treasury_fee: u64,
+        treasury_x: u64,
+        treasury_y: u64,
+    ) -> BalancePool {
+        return BalancePool {
             id: PoolId::from((
                 ScriptHash::from([
                     162, 206, 112, 95, 150, 240, 52, 167, 61, 102, 158, 92, 11, 47, 25, 41, 48, 224, 188,
@@ -647,11 +794,11 @@ mod tests {
                     ],
                 )),
             )),
-            reserves_x: TaggedAmount::new(2115301811439),
+            reserves_x: TaggedAmount::new(reserves_x),
             weight_x: 1,
-            reserves_y: TaggedAmount::new(27887555508598),
+            reserves_y: TaggedAmount::new(reserves_y),
             weight_y: 4,
-            liquidity: TaggedAmount::new(0),
+            liquidity: TaggedAmount::new(liquidity),
             asset_x: TaggedAssetClass::new(AssetClass::Native),
             asset_y: TaggedAssetClass::new(AssetClass::Token((
                 ScriptHash::from([
@@ -679,11 +826,11 @@ mod tests {
                     ],
                 )),
             ))),
-            lp_fee_x: Ratio::new_raw(99000, 100000),
-            lp_fee_y: Ratio::new_raw(99000, 100000),
-            treasury_fee: Ratio::new_raw(100, 100000),
-            treasury_x: TaggedAmount::new(1143236614),
-            treasury_y: TaggedAmount::new(3057757049),
+            lp_fee_x: Ratio::new_raw(lp_fee_x, 100000),
+            lp_fee_y: Ratio::new_raw(lp_fee_y, 100000),
+            treasury_fee: Ratio::new_raw(treasury_fee, 100000),
+            treasury_x: TaggedAmount::new(treasury_x),
+            treasury_y: TaggedAmount::new(treasury_y),
             ver: BalancePoolVer::V1,
             marginal_cost: ExUnits {
                 mem: 120000000,
@@ -691,6 +838,28 @@ mod tests {
             },
             min_pool_lovelace: 10000000000,
         };
+    }
+
+    #[test]
+    fn parse_balance_pool_datum() {
+        let pd = PlutusData::from_cbor_bytes(&*hex::decode(DATUM_SAMPLE).unwrap()).unwrap();
+        let maybe_conf = BalancePoolConfig::try_from_pd(pd);
+        assert!(maybe_conf.is_some())
+    }
+
+    #[test]
+    fn swap() {
+        let pool = gen_ada_token_pool(
+            2115301811439,
+            27887555508598,
+            0,
+            99000,
+            99000,
+            100,
+            1143236614,
+            3057757049,
+        );
+
         let result = pool.swap(Side::Ask(200000000));
 
         assert_eq!(result.0, 652178037)
@@ -698,64 +867,7 @@ mod tests {
 
     #[test]
     fn swap_redeemer_test() {
-        let pool = BalancePool {
-            id: PoolId::from((
-                ScriptHash::from([
-                    162, 206, 112, 95, 150, 240, 52, 167, 61, 102, 158, 92, 11, 47, 25, 41, 48, 224, 188,
-                    211, 138, 203, 127, 107, 246, 89, 115, 157,
-                ]),
-                AssetName::from((
-                    3,
-                    [
-                        110, 102, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                        0, 0, 0, 0, 0, 0,
-                    ],
-                )),
-            )),
-            reserves_x: TaggedAmount::new(200000000),
-            weight_x: 1,
-            reserves_y: TaggedAmount::new(84093845),
-            weight_y: 4,
-            liquidity: TaggedAmount::new(0),
-            asset_x: TaggedAssetClass::new(AssetClass::Native),
-            asset_y: TaggedAssetClass::new(AssetClass::Token((
-                ScriptHash::from([
-                    75, 52, 89, 253, 24, 161, 219, 171, 226, 7, 205, 25, 201, 149, 26, 159, 172, 159, 92, 15,
-                    156, 56, 78, 61, 151, 239, 186, 38,
-                ]),
-                AssetName::from((
-                    5,
-                    [
-                        116, 101, 115, 116, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                        0, 0, 0, 0, 0, 0, 0,
-                    ],
-                )),
-            ))),
-            asset_lq: TaggedAssetClass::new(AssetClass::Token((
-                ScriptHash::from([
-                    114, 191, 27, 172, 195, 20, 1, 41, 111, 158, 228, 210, 254, 123, 132, 165, 36, 56, 38,
-                    251, 3, 233, 206, 25, 51, 218, 254, 192,
-                ]),
-                AssetName::from((
-                    2,
-                    [
-                        108, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                        0, 0, 0, 0, 0,
-                    ],
-                )),
-            ))),
-            lp_fee_x: Ratio::new_raw(99970, 100000),
-            lp_fee_y: Ratio::new_raw(99970, 100000),
-            treasury_fee: Ratio::new_raw(10, 100000),
-            treasury_x: TaggedAmount::new(10000),
-            treasury_y: TaggedAmount::new(0),
-            ver: BalancePoolVer::V1,
-            marginal_cost: ExUnits {
-                mem: 120000000,
-                steps: 100000000000,
-            },
-            min_pool_lovelace: 1000000000,
-        };
+        let pool = gen_ada_token_pool(200000000, 84093845, 0, 99970, 99970, 10, 10000, 0);
 
         let (_result, new_pool) = pool.clone().swap(Side::Ask(363613802862));
 
@@ -775,84 +887,29 @@ mod tests {
 
     #[test]
     fn deposit_redeemer_test() {
-        let pool_id = PoolId::from((
-            ScriptHash::from([
-                162, 206, 112, 95, 150, 240, 52, 167, 61, 102, 158, 92, 11, 47, 25, 41, 48, 224, 188, 211,
-                138, 203, 127, 107, 246, 89, 115, 157,
-            ]),
-            AssetName::from((
-                3,
-                [
-                    110, 102, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                    0, 0, 0, 0,
-                ],
-            )),
-        ));
-
-        let token_x = TaggedAssetClass::new(AssetClass::Native);
-        let token_y = TaggedAssetClass::new(AssetClass::Token((
-            ScriptHash::from([
-                75, 52, 89, 253, 24, 161, 219, 171, 226, 7, 205, 25, 201, 149, 26, 159, 172, 159, 92, 15,
-                156, 56, 78, 61, 151, 239, 186, 38,
-            ]),
-            AssetName::from((
-                5,
-                [
-                    116, 101, 115, 116, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                    0, 0, 0, 0, 0,
-                ],
-            )),
-        )));
-
-        let token_lq = TaggedAssetClass::new(AssetClass::Token((
-            ScriptHash::from([
-                114, 191, 27, 172, 195, 20, 1, 41, 111, 158, 228, 210, 254, 123, 132, 165, 36, 56, 38, 251,
-                3, 233, 206, 25, 51, 218, 254, 192,
-            ]),
-            AssetName::from((
-                2,
-                [
-                    108, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                    0, 0, 0, 0,
-                ],
-            )),
-        )));
-
-        let pool = BalancePool {
-            id: pool_id,
-            reserves_x: TaggedAmount::new(152570837),
-            weight_x: 1,
-            reserves_y: TaggedAmount::new(42092),
-            weight_y: 4,
-            liquidity: TaggedAmount::new(MAX_LQ_CAP - 9223372036854560080),
-            asset_x: token_x,
-            asset_y: token_y,
-            asset_lq: token_lq,
-            lp_fee_x: Ratio::new_raw(99000, 100000),
-            lp_fee_y: Ratio::new_raw(99000, 100000),
-            treasury_fee: Ratio::new_raw(100, 100000),
-            treasury_x: TaggedAmount::new(354535),
-            treasury_y: TaggedAmount::new(121),
-            ver: BalancePoolVer::V1,
-            marginal_cost: ExUnits {
-                mem: 120000000,
-                steps: 100000000000,
-            },
-            min_pool_lovelace: 100000000000,
-        };
+        let pool = gen_ada_token_pool(
+            1981759952,
+            53144,
+            9223372036854587823,
+            99000,
+            99000,
+            100,
+            13000,
+            94,
+        );
 
         const TX: &str = "6c038a69587061acd5611507e68b1fd3a7e7d189367b7853f3bb5079a118b880";
         const IX: u64 = 1;
 
         let test_order: ClassicalOnChainRedeem = ClassicalOrder {
             id: OnChainOrderId(OutputRef::new(TransactionHash::from_hex(TX).unwrap(), IX)),
-            pool_id: pool_id,
+            pool_id: pool.id,
             order: Redeem {
-                pool_nft: pool_id,
-                token_x: token_x,
-                token_y: token_y,
-                token_lq: token_lq,
-                token_lq_amount: TaggedAmount::new(1581993),
+                pool_nft: pool.id,
+                token_x: pool.asset_x,
+                token_y: pool.asset_y,
+                token_lq: pool.asset_lq,
+                token_lq_amount: TaggedAmount::new(1900727),
                 ex_fee: 1500000,
                 reward_pkh: Ed25519KeyHash::from([0u8; 28]),
                 reward_stake_pkh: None,
@@ -867,4 +924,31 @@ mod tests {
 
         assert_eq!(1, 1)
     }
+
+    #[test]
+    #[test]
+    fn available_liquidity_test() {
+        let pool = gen_ada_token_pool(2105999997, 1981759952, 9223372036854587823, 99000, 99000, 0, 0, 0);
+
+        // Repair available volumes from average sell price impact.
+        let max_target_price_impact = Ratio::new_raw(45035996273705, 2251799813685248);
+
+        let (available_liquidity_quote_ask, _) =
+            pool.available_liquidity_by_user_impact(Ask(max_target_price_impact));
+        let (available_liquidity_quote_bid, _) =
+            pool.available_liquidity_by_user_impact(Bid(max_target_price_impact));
+
+        assert_eq!(available_liquidity_quote_ask, 15918267);
+        assert_eq!(available_liquidity_quote_bid, 67120253);
+
+        // Repair available volumes from pool spot price impact.
+        let max_spot_price_impact = Ratio::new_raw(355981766792995, 9007199254740992);
+
+        let (quote_qty_ask_spot, _) = pool.available_liquidity_by_spot_impact(Ask(max_spot_price_impact));
+
+        let (quote_qty_bid_spot, _) = pool.available_liquidity_by_spot_impact(Bid(max_spot_price_impact));
+
+        assert_eq!(quote_qty_ask_spot, 15918267);
+        assert_eq!(quote_qty_bid_spot, 66853939)
+    }
 }
diff --git a/spectrum-offchain-cardano/src/data/cfmm_pool.rs b/spectrum-offchain-cardano/src/data/cfmm_pool.rs
index c7d899f3b..877a0bdac 100644
--- a/spectrum-offchain-cardano/src/data/cfmm_pool.rs
+++ b/spectrum-offchain-cardano/src/data/cfmm_pool.rs
@@ -1,20 +1,23 @@
+use std::fmt::Debug;
+use std::ops::Div;
+
+use bignumber::BigNumber;
 use cml_chain::address::Address;
 use cml_chain::assets::MultiAsset;
 use cml_chain::certs::StakeCredential;
-use std::fmt::Debug;
-
 use cml_chain::plutus::{ConstrPlutusData, PlutusData};
 use cml_chain::transaction::{ConwayFormatTxOut, DatumOption, TransactionOutput};
 use cml_chain::utils::BigInteger;
 use cml_chain::Value;
-
 use cml_multi_era::babbage::BabbageTransactionOutput;
+use dashu_float::DBig;
 use num_integer::Roots;
 use num_rational::Ratio;
+use num_traits::ToPrimitive;
 use num_traits::{CheckedAdd, CheckedSub};
 use type_equalities::IsEqual;
 
-use bloom_offchain::execution_engine::liquidity_book::pool::{Pool, PoolQuality, StaticPrice};
+use bloom_offchain::execution_engine::liquidity_book::market_maker::{MarketMaker, PoolQuality, SpotPrice};
 use bloom_offchain::execution_engine::liquidity_book::side::{Side, SideM};
 use bloom_offchain::execution_engine::liquidity_book::types::AbsolutePrice;
 use spectrum_cardano_lib::ex_units::ExUnits;
@@ -29,23 +32,17 @@ use spectrum_offchain::data::{Has, Stable};
 use spectrum_offchain::ledger::{IntoLedger, TryFromLedger};
 
 use crate::constants::{FEE_DEN, LEGACY_FEE_NUM_MULTIPLIER, MAX_LQ_CAP};
-
 use crate::data::deposit::ClassicalOnChainDeposit;
-
 use crate::data::fee_switch_bidirectional_fee::FeeSwitchBidirectionalPoolConfig;
-
+use crate::data::fee_switch_pool::FeeSwitchPoolConfig;
 use crate::data::limit_swap::ClassicalOnChainLimitSwap;
 use crate::data::operation_output::{DepositOutput, RedeemOutput, SwapOutput};
 use crate::data::order::{Base, ClassicalOrder, PoolNft, Quote};
 use crate::data::pair::order_canonical;
-
 use crate::data::pool::{
     ApplyOrder, ApplyOrderError, AssetDeltas, ImmutablePoolUtxo, Lq, PoolBounds, Rx, Ry,
 };
 use crate::data::redeem::ClassicalOnChainRedeem;
-
-use crate::data::fee_switch_pool::FeeSwitchPoolConfig;
-use crate::data::pool::ApplyOrderError::Incompatible;
 use crate::data::PoolId;
 use crate::deployment::ProtocolValidator::{
     ConstFnPoolFeeSwitch, ConstFnPoolFeeSwitchBiDirFee, ConstFnPoolV1, ConstFnPoolV2,
@@ -282,10 +279,10 @@ where
     }
 }
 
-impl Pool for ConstFnPool {
+impl MarketMaker for ConstFnPool {
     type U = ExUnits;
 
-    fn static_price(&self) -> StaticPrice {
+    fn static_price(&self) -> SpotPrice {
         let x = self.asset_x.untag();
         let y = self.asset_y.untag();
         let [base, _] = order_canonical(x, y);
@@ -370,7 +367,7 @@ impl Pool for ConstFnPool {
         self.marginal_cost
     }
 
-    fn swaps_allowed(&self) -> bool {
+    fn is_active(&self) -> bool {
         let lq_bound = (self.reserves_x.untag() * 2) >= self.lq_lower_bound.untag();
         let bot_bound = if self.asset_x.is_native() {
             self.reserves_x.untag() >= self.min_pool_lovelace
@@ -379,6 +376,109 @@ impl Pool for ConstFnPool {
         };
         lq_bound && bot_bound
     }
+
+    fn available_liquidity_by_user_impact(&self, max_user_price_impact: Side<Ratio<u64>>) -> (u64, u64) {
+        // "max_user_price_impact" is calculated as
+        // "max_user_price_impact = 1 - avg_sell_price / market_price" to be always > 0.
+        // Outputs are ("quote_amount_available", "base_amount_required").
+        // Outputs reflects how many quote asset the user will receive and how many base asset
+        // must be added to the pool in order for this operation to occur with a given
+        // "max_price_impact" relative to the current state of the pool.
+        // Note: all calculations are made taking fees into account, thus "max_user_price_impact"
+        // must also include fees in "market_price" calculation.
+        const BN_ONE: BigNumber = BigNumber { value: DBig::ONE };
+        let sqrt_degree = BigNumber::from(0.5);
+
+        let (tradable_reserves_base, tradable_reserves_quote, total_fee_mult) = match max_user_price_impact {
+            Side::Bid(_) => (
+                BigNumber::from((self.reserves_y - self.treasury_y).untag() as f64),
+                BigNumber::from((self.reserves_x - self.treasury_x).untag() as f64),
+                BigNumber::from((self.lp_fee_y - self.treasury_fee).to_f64().unwrap()),
+            ),
+            Side::Ask(_) => (
+                BigNumber::from((self.reserves_x - self.treasury_x).untag() as f64),
+                BigNumber::from((self.reserves_y - self.treasury_y).untag() as f64),
+                BigNumber::from((self.lp_fee_x - self.treasury_fee).to_f64().unwrap()),
+            ),
+        };
+
+        let lq_balance = (tradable_reserves_base.clone() * tradable_reserves_quote.clone()).pow(&sqrt_degree);
+
+        let market_price = tradable_reserves_quote
+            .clone()
+            .div(tradable_reserves_base.clone())
+            * total_fee_mult.clone();
+
+        let impact_price = market_price
+            * (BN_ONE
+                - BigNumber::from(*max_user_price_impact.unwrap().numer() as f64)
+                    .div(BigNumber::from(*max_user_price_impact.unwrap().denom() as f64)))
+            .div(total_fee_mult.clone());
+
+        let p1 =
+            (impact_price * lq_balance.clone() / tradable_reserves_quote.clone()).pow(&(BigNumber::from(2)));
+        let p1_sqrt = p1.clone().pow(&sqrt_degree);
+        let x1 = lq_balance.clone() / p1_sqrt.clone();
+        let y1 = lq_balance.clone() * p1_sqrt.clone();
+
+        let base = (x1.clone() - tradable_reserves_base.clone()) / total_fee_mult;
+        let quote = tradable_reserves_quote - y1.clone();
+
+        return (
+            <u64>::try_from(quote.to_precision(0).value.to_int().value()).unwrap(),
+            <u64>::try_from(base.to_precision(0).value.to_int().value()).unwrap(),
+        );
+    }
+    fn available_liquidity_by_spot_impact(&self, max_spot_price_impact: Side<Ratio<u64>>) -> (u64, u64) {
+        // "max_spot_price_impact" is calculated as
+        // "max_spot_price_impact = 1 - market_price_new / market_price" to be always > 0.
+        // Outputs are ("quote_amount_available", "base_amount_required").
+        // Outputs reflects how many quote asset the user will receive and how many base asset
+        // must be added to the pool in order for this operation to occur with a given
+        // "max_spot_price_impact" relative to the current state of the pool.
+        // Note: all calculations are made taking fees into account, thus "max_spot_price_impact"
+        // must also include fees in "market_price" calculation.
+        const BN_ONE: BigNumber = BigNumber { value: DBig::ONE };
+        let sqrt_degree = BigNumber::from(0.5);
+
+        let (tradable_reserves_base, tradable_reserves_quote, total_fee_mult) = match max_spot_price_impact {
+            Side::Bid(_) => (
+                BigNumber::from((self.reserves_y - self.treasury_y).untag() as f64),
+                BigNumber::from((self.reserves_x - self.treasury_x).untag() as f64),
+                BigNumber::from((self.lp_fee_y - self.treasury_fee).to_f64().unwrap()),
+            ),
+            Side::Ask(_) => (
+                BigNumber::from((self.reserves_x - self.treasury_x).untag() as f64),
+                BigNumber::from((self.reserves_y - self.treasury_y).untag() as f64),
+                BigNumber::from((self.lp_fee_x - self.treasury_fee).to_f64().unwrap()),
+            ),
+        };
+
+        let lq_balance = (tradable_reserves_base.clone() * tradable_reserves_quote.clone()).pow(&sqrt_degree);
+
+        let market_price = tradable_reserves_quote
+            .clone()
+            .div(tradable_reserves_base.clone())
+            * total_fee_mult.clone();
+
+        let impact_price = market_price
+            * (BN_ONE
+                - BigNumber::from(*max_spot_price_impact.unwrap().numer() as f64)
+                    .div(BigNumber::from(*max_spot_price_impact.unwrap().denom() as f64)))
+            .div(total_fee_mult.clone());
+
+        let p1_sqrt = impact_price.clone().pow(&sqrt_degree);
+        let x1 = lq_balance.clone() / p1_sqrt.clone();
+        let y1 = lq_balance.clone() * p1_sqrt.clone();
+
+        let base = (x1.clone() - tradable_reserves_base.clone()) / total_fee_mult;
+        let quote = tradable_reserves_quote - y1.clone();
+
+        return (
+            <u64>::try_from(quote.to_precision(0).value.to_int().value()).unwrap(),
+            <u64>::try_from(base.to_precision(0).value.to_int().value()).unwrap(),
+        );
+    }
 }
 
 impl Has<ConstFnPoolVer> for ConstFnPool {
@@ -718,20 +818,29 @@ impl ApplyOrder<ClassicalOnChainRedeem> for ConstFnPool {
 }
 
 mod tests {
-    use crate::data::balance_pool::{BalancePool, BalancePoolRedeemer, BalancePoolVer};
-    use crate::data::cfmm_pool::{ConstFnPool, ConstFnPoolVer};
-    use crate::data::pool::CFMMPoolAction;
-    use crate::data::PoolId;
-    use bloom_offchain::execution_engine::liquidity_book::pool::Pool;
-    use bloom_offchain::execution_engine::liquidity_book::side::Side;
     use cml_crypto::ScriptHash;
     use num_rational::Ratio;
+
+    use bloom_offchain::execution_engine::liquidity_book::market_maker::MarketMaker;
+    use bloom_offchain::execution_engine::liquidity_book::side::Side;
+    use bloom_offchain::execution_engine::liquidity_book::side::Side::{Ask, Bid};
     use spectrum_cardano_lib::ex_units::ExUnits;
     use spectrum_cardano_lib::{AssetClass, AssetName, TaggedAmount, TaggedAssetClass};
 
-    #[test]
-    fn treasury_x_test() {
-        let pool = ConstFnPool {
+    use crate::data::cfmm_pool::{ConstFnPool, ConstFnPoolVer};
+    use crate::data::PoolId;
+
+    fn gen_ada_token_pool(
+        reserves_x: u64,
+        reserves_y: u64,
+        liquidity: u64,
+        lp_fee_x: u64,
+        lp_fee_y: u64,
+        treasury_fee: u64,
+        treasury_x: u64,
+        treasury_y: u64,
+    ) -> ConstFnPool {
+        return ConstFnPool {
             id: PoolId::from((
                 ScriptHash::from([
                     162, 206, 112, 95, 150, 240, 52, 167, 61, 102, 158, 92, 11, 47, 25, 41, 48, 224, 188,
@@ -745,9 +854,9 @@ mod tests {
                     ],
                 )),
             )),
-            reserves_x: TaggedAmount::new(1632109645),
-            reserves_y: TaggedAmount::new(1472074052),
-            liquidity: TaggedAmount::new(0),
+            reserves_x: TaggedAmount::new(reserves_x),
+            reserves_y: TaggedAmount::new(reserves_y),
+            liquidity: TaggedAmount::new(liquidity),
             asset_x: TaggedAssetClass::new(AssetClass::Native),
             asset_y: TaggedAssetClass::new(AssetClass::Token((
                 ScriptHash::from([
@@ -775,16 +884,21 @@ mod tests {
                     ],
                 )),
             ))),
-            lp_fee_x: Ratio::new_raw(99970, 100000),
-            lp_fee_y: Ratio::new_raw(99970, 100000),
-            treasury_fee: Ratio::new_raw(10, 100000),
-            treasury_x: TaggedAmount::new(11500),
-            treasury_y: TaggedAmount::new(2909),
+            lp_fee_x: Ratio::new_raw(lp_fee_x, 100000),
+            lp_fee_y: Ratio::new_raw(lp_fee_y, 100000),
+            treasury_fee: Ratio::new_raw(treasury_fee, 100000),
+            treasury_x: TaggedAmount::new(treasury_x),
+            treasury_y: TaggedAmount::new(treasury_y),
             lq_lower_bound: TaggedAmount::new(0),
             ver: ConstFnPoolVer::FeeSwitch,
             marginal_cost: ExUnits { mem: 100, steps: 100 },
             min_pool_lovelace: 10000000,
         };
+    }
+
+    #[test]
+    fn treasury_x_test() {
+        let pool = gen_ada_token_pool(1632109645, 1472074052, 0, 99970, 99970, 10, 11500, 2909);
 
         let (_, new_pool) = pool.clone().swap(Side::Ask(900000000));
 
@@ -792,4 +906,33 @@ mod tests {
 
         assert_eq!(new_pool.treasury_x.untag(), correct_x_treasury)
     }
+
+    #[test]
+    fn available_liquidity_test() {
+        let fee_num = 98500;
+        let reserves_x = 1116854094529;
+        let reserves_y = 4602859113047;
+
+        let pool = gen_ada_token_pool(reserves_x, reserves_y, 0, fee_num, fee_num, 0, 0, 0);
+
+        // Repair available volumes from average sell price impact.
+        let max_target_price_impact = Ratio::new_raw(45035996273705, 4503599627370496);
+
+        let (quote_qty_ask, _) = pool.available_liquidity_by_user_impact(Ask(max_target_price_impact));
+
+        let (quote_qty_bid, _) = pool.available_liquidity_by_user_impact(Bid(max_target_price_impact));
+
+        assert_eq!(quote_qty_ask, 46028591130);
+        assert_eq!(quote_qty_bid, 11168540945);
+
+        // Repair available volumes from pool spot price impact.
+        let max_spot_price_impact = Ratio::new_raw(179243265169347, 9007199254740992);
+
+        let (quote_qty_ask_spot, _) = pool.available_liquidity_by_spot_impact(Ask(max_spot_price_impact));
+
+        let (quote_qty_bid_spot, _) = pool.available_liquidity_by_spot_impact(Bid(max_spot_price_impact));
+
+        assert_eq!(quote_qty_ask_spot, 46028591130);
+        assert_eq!(quote_qty_bid_spot, 11168540945)
+    }
 }
diff --git a/spectrum-offchain-cardano/src/data/pool.rs b/spectrum-offchain-cardano/src/data/pool.rs
index 99f993ac6..e673b1eea 100644
--- a/spectrum-offchain-cardano/src/data/pool.rs
+++ b/spectrum-offchain-cardano/src/data/pool.rs
@@ -17,10 +17,11 @@ use cml_chain::{Coin, PolicyId};
 
 use cml_multi_era::babbage::BabbageTransactionOutput;
 use log::info;
+use num_rational::Ratio;
 use tracing_subscriber::filter::combinator::Or;
 
 use bloom_offchain::execution_engine::bundled::Bundled;
-use bloom_offchain::execution_engine::liquidity_book::pool::{Pool, PoolQuality, StaticPrice};
+use bloom_offchain::execution_engine::liquidity_book::market_maker::{MarketMaker, PoolQuality, SpotPrice};
 use bloom_offchain::execution_engine::liquidity_book::side::Side;
 use bloom_offchain::execution_engine::liquidity_book::types::AbsolutePrice;
 use spectrum_cardano_lib::collateral::Collateral;
@@ -242,9 +243,9 @@ pub struct AssetDeltas {
     pub asset_to_add_to: AssetClass,
 }
 
-impl Pool for AnyPool {
+impl MarketMaker for AnyPool {
     type U = ExUnits;
-    fn static_price(&self) -> StaticPrice {
+    fn static_price(&self) -> SpotPrice {
         match self {
             PureCFMM(p) => p.static_price(),
             BalancedCFMM(p) => p.static_price(),
@@ -285,10 +286,24 @@ impl Pool for AnyPool {
         }
     }
 
-    fn swaps_allowed(&self) -> bool {
+    fn available_liquidity_by_spot_impact(&self, max_spot_price_impact: Side<Ratio<u64>>) -> (u64, u64) {
         match self {
-            PureCFMM(p) => p.swaps_allowed(),
-            BalancedCFMM(p) => p.swaps_allowed(),
+            PureCFMM(p) => p.available_liquidity_by_spot_impact(max_spot_price_impact),
+            BalancedCFMM(p) => p.available_liquidity_by_spot_impact(max_spot_price_impact),
+        }
+    }
+
+    fn available_liquidity_by_user_impact(&self, max_user_price_impact: Side<Ratio<u64>>) -> (u64, u64) {
+        match self {
+            PureCFMM(p) => p.available_liquidity_by_user_impact(max_user_price_impact),
+            BalancedCFMM(p) => p.available_liquidity_by_user_impact(max_user_price_impact),
+        }
+    }
+
+    fn is_active(&self) -> bool {
+        match self {
+            PureCFMM(p) => p.is_active(),
+            BalancedCFMM(p) => p.is_active(),
         }
     }
 }
@@ -521,7 +536,7 @@ pub mod tests {
     use cml_crypto::TransactionHash;
     use rand::Rng;
 
-    use bloom_offchain::execution_engine::liquidity_book::{pool::Pool, side::Side};
+    use bloom_offchain::execution_engine::liquidity_book::{market_maker::MarketMaker, side::Side};
     use spectrum_cardano_lib::OutputRef;
     use spectrum_offchain::ledger::TryFromLedger;
 
