@@ -224,23 +224,22 @@ func (ms msgServer) CreateLease(goCtx context.Context, msg *mvbeta.MsgCreateLeas
224224 ms .keepers .Market .OnOrderMatched (ctx , order )
225225 ms .keepers .Market .OnBidMatched (ctx , bid )
226226
227- // close losing bids
228- //
229- // Every other BID_OPEN on this order must run OnBidLost. Do not stop the loop when
230- // AccountClose fails: returning true from the callback skips remaining bids, leaving them
231- // BID_OPEN while the winning lease is already committed (mainnet-visible bug).
227+ // Close every other open bid's escrow, then mark the bid lost. If AccountClose fails,
228+ // abort the whole message so we never commit BID_LOST with bid escrow still open (and
229+ // the lease / payment / matched state rolls back with the tx).
230+ var loserCloseErr error
232231 ms .keepers .Market .WithBidsForOrder (ctx , msg .BidID .OrderID (), mvbeta .BidOpen , func (cbid mvbeta.Bid ) bool {
233- ms .keepers .Market .OnBidLost (ctx , cbid )
234-
235- if closeErr := ms .keepers .Escrow .AccountClose (ctx , cbid .ID .ToEscrowAccountID ()); closeErr != nil {
236- ctx .Logger ().Error (
237- "escrow AccountClose failed for losing bid after lease created; bid already marked lost" ,
238- "bid" , cbid .ID .String (),
239- "error" , closeErr ,
240- )
232+ if err := ms .keepers .Escrow .AccountClose (ctx , cbid .ID .ToEscrowAccountID ()); err != nil {
233+ loserCloseErr = err
234+ return true
241235 }
236+ ms .keepers .Market .OnBidLost (ctx , cbid )
242237 return false
243238 })
239+ if loserCloseErr != nil {
240+ return & mvbeta.MsgCreateLeaseResponse {}, fmt .Errorf (
241+ "escrow AccountClose for losing bid: %w" , loserCloseErr )
242+ }
244243
245244 return & mvbeta.MsgCreateLeaseResponse {}, nil
246245}
0 commit comments