@@ -8,6 +8,8 @@ import DA.Optional
88import DA.Foldable hiding (elem, null, length)
99import DA.List
1010import Daml.Trigger
11+ import DA.Map (Map)
12+ import DA.Map qualified as Map
1113
1214import qualified Marketplace.Trading.Model as Order
1315import qualified Marketplace.Trading.Service as Service
@@ -18,11 +20,16 @@ import qualified Marketplace.Trading.Matching.Service as Matching
1820import Utils
1921import DA.Finance.Asset (AssetDeposit)
2022
21- type CurrentOrderId = Int
23+ type OrderMap = Map (Party, Text) (ContractPair Order.T)
2224
23- handleMatching : Trigger CurrentOrderId
25+ data MatchingState = MatchingState with
26+ currentOrderId : Int
27+ remainingOrders : OrderMap
28+ deriving (Show, Eq)
29+
30+ handleMatching : Trigger MatchingState
2431handleMatching = Trigger
25- { initialize = return 0
32+ { initialize = return $ MatchingState with currentOrderId = 0; remainingOrders = mempty
2633 , updateState = \_ -> pure ()
2734 , rule = handleMatchingRule
2835 , registeredTemplates = RegisteredTemplates [ registeredTemplate @ListingService.Service
@@ -36,7 +43,12 @@ handleMatching = Trigger
3643 , heartbeat = None
3744 }
3845
39- handleMatchingRule : Party -> TriggerA CurrentOrderId ()
46+ modifyRemainingOrders : (OrderMap -> OrderMap) -> TriggerA MatchingState ()
47+ modifyRemainingOrders fn = do
48+ state <- get
49+ put $ state with remainingOrders = fn state.remainingOrders
50+
51+ handleMatchingRule : Party -> TriggerA MatchingState ()
4052handleMatchingRule party = do
4153 debug "Running matching rule..."
4254
@@ -46,7 +58,7 @@ handleMatchingRule party = do
4658 [(_, feeSchedule):xs] -> feeSchedule.currentFee.amount
4759 _ -> 0.0
4860
49- -- Acknowledge all 'Order.Request' and update current ID │
61+ -- Acknowledge all 'Order.Request' and update current ID
5062 orderRequests <- query @Service.CreateOrderRequest
5163 deposits <- query @AssetDeposit
5264 forA_ orderRequests \(cid,or) -> do
@@ -56,10 +68,10 @@ handleMatchingRule party = do
5668 if exchangeFeeAmount < currentFee
5769 then void $ emitExerciseCmd cid Service.RejectRequest with errorCode = 790; errorMessage = "Fee requirement not met"
5870 else do
59- currentOrderId <- get
60- emitExerciseCmd cid Service.AcknowledgeRequest with providerOrderId = show currentOrderId
71+ state <- get
72+ emitExerciseCmd cid Service.AcknowledgeRequest with providerOrderId = show $ state. currentOrderId
6173 debug "Acknowledging order"
62- modify (+1)
74+ put $ state with currentOrderId = state.currentOrderId + 1
6375
6476 time <- getTime
6577 -- Acknowledge all 'Order.CancelRequest'
@@ -78,20 +90,34 @@ handleMatchingRule party = do
7890
7991 -- Check for matches on all 'Order'
8092 orders <- query @Order.T
81- forA_ orders (handleOrder party orders)
93+
94+ state <- get
95+ let remainingOrders = Map.fromList $ map (\op -> (key op._2, op))
96+ $ filter (\(_,o) -> shouldProcess o) orders
97+ put $ state with remainingOrders
98+ matchOrders party $ sortOn (\(_,o) -> o.createdAt) $ Map.values remainingOrders
99+
100+ -- |Match all orders removing orders that are matched or do not have any match
101+ matchOrders : Party -> [ContractPair Order.T] -> TriggerA MatchingState ()
102+ matchOrders party [] = return ()
103+ matchOrders party (order::orders) = do
104+ matchOrder party orders order
105+ newOrders <- sortOn (\(_,o) -> o.createdAt) . Map.values . remainingOrders <$> get
106+ matchOrders party newOrders
107+
108+ -- |Order can be matched
109+ shouldProcess : Order.T -> Bool
110+ shouldProcess o = o.status `elem` [Order.PendingExecution, Order.PartiallyExecuted]
82111
83112-- |Check for crossing orders. If found, fill both orders. Matches by price.
84- handleOrder : Party -> [ContractPair Order.T] -> ContractPair Order.T -> TriggerA CurrentOrderId ()
85- handleOrder party orders op@(orderCid, order) = do
113+ matchOrder : Party -> [ContractPair Order.T] -> ContractPair Order.T -> TriggerA MatchingState ()
114+ matchOrder party orders op@(orderCid, order) = do
86115 debug $ "Handling order: " <> show order
87-
88- case order.status of
89- Order.PendingExecution -> processOrder op
90- Order.PartiallyExecuted -> processOrder op
91- _ -> debug $ "Ignoring order in status: " <> show order.status
116+ processOrder op
117+ modifyRemainingOrders (Map.delete $ key order)
92118
93119 where
94- processOrder : ContractPair Order.T -> TriggerA CurrentOrderId ()
120+ processOrder : ContractPair Order.T -> TriggerA MatchingState ()
95121 processOrder (orderCid, order) = do
96122 let oppositelimitOrders = sortOn (\(_,x) -> case x.details.orderType of
97123 Order.Limit price -> price
@@ -130,7 +156,7 @@ handleOrder party orders op@(orderCid, order) = do
130156 Order.Limit _ -> True
131157 _ -> False
132158
133- fill : ContractPair Order.T -> ContractPair Order.T -> TriggerA CurrentOrderId ()
159+ fill : ContractPair Order.T -> ContractPair Order.T -> TriggerA MatchingState ()
134160 fill (aggressiveCid, aggressive) (passiveCid, passive) = do
135161 debug $ "Matching order: " <> show aggressive.details.id <> " to : " <> show passive.details.id
136162
@@ -149,4 +175,6 @@ handleOrder party orders op@(orderCid, order) = do
149175
150176 emitCommands [exerciseByKeyCmd @Matching.Service aggressive.provider Matching.MatchOrders with execution] [toAnyContractId aggressiveCid, toAnyContractId passiveCid]
151177
178+ modifyRemainingOrders (Map.delete $ key passive)
179+
152180 return ()
0 commit comments