How Akash Implements Bid Matching and Lease Creation in the Market Module
Akash implements bid matching and lease creation through a state-transition workflow in the market module that marks winning orders and bids as active, creates payment escrows, stores lease records, and closes all competing bids as lost.
The bid matching and lease creation process in the Akash Network is coordinated by the market module, which manages the lifecycle of deployment orders, provider bids, and active leases. Located in the akash-network/node repository, this module ensures atomic transactions that either complete a lease creation entirely or roll back without side effects. Understanding this flow is essential for developers building on Akash or auditing its decentralized compute marketplace.
The Lease Creation Orchestration
The entry point for bid matching is the CreateLease method in the message handler server. When a user submits a MsgCreateLease transaction, the handler validates the entities, establishes payment infrastructure, and executes state transitions.
The high-level flow follows four distinct phases:
- Validation – Load and verify the bid, order, and deployment group are in the correct open state.
- Escrow Setup – Create a payment escrow to lock funds for the lease duration.
- State Activation – Mark the order and winning bid as matched (active).
- Cleanup – Close all competing bids and their escrow accounts.
The implementation in x/market/handler/server.go (lines 78-226) handles this sequence:
func (ms msgServer) CreateLease(goCtx context.Context, msg *types.MsgCreateLease) (*types.MsgCreateLeaseResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// 1️⃣ Load and validate the bid, order and deployment group
bid, _ := ms.keepers.Market.GetBid(ctx, msg.BidID)
order, _ := ms.keepers.Market.GetOrder(ctx, msg.BidID.OrderID())
group, _ := ms.keepers.Deployment.GetGroup(ctx, order.ID.GroupID())
// 2️⃣ Create the escrow payment that will hold the lease fee
err := ms.keepers.Escrow.PaymentCreate(ctx,
msg.BidID.LeaseID().ToEscrowPaymentID(),
provider, // provider address extracted from the bid ID
bid.Price) // price agreed in the winning bid
if err != nil { return nil, err }
// 3️⃣ Store the lease record
if err = ms.keepers.Market.CreateLease(ctx, bid); err != nil {
return nil, err
}
// 4️⃣ Mark the order and the winning bid as matched (active)
ms.keepers.Market.OnOrderMatched(ctx, order)
ms.keepers.Market.OnBidMatched(ctx, bid)
// … (losing bids handling – see next section)
return &types.MsgCreateLeaseResponse{}, nil
}
Matching State Transitions
Once the lease record is created, the system must update the market state to reflect that the order is fulfilled and the specific bid has won.
Activating the Order
The OnOrderMatched function in x/market/keeper/keeper.go (lines 79-84) transitions the order from open to active. This helper reads the current order state, sets order.State = types.OrderActive, and delegates storage to updateOrder, which uses collections.IndexedMap to maintain secondary indexes.
Activating the Winning Bid
Similarly, OnBidMatched (lines 86-90) handles the bid state transition by setting bid.State = types.BidActive before calling updateBid. Both functions ensure that the underlying IndexedMap structures remain consistent, allowing efficient lookups by state and provider.
Closing Competing Bids
After establishing the winning lease, the system must invalidate all other open bids for the same order. The handler iterates through competing bids using WithBidsForOrder, marks each as lost, and closes their escrow accounts.
The cleanup logic in x/market/handler/server.go:
// close losing bids
ms.keepers.Market.WithBidsForOrder(ctx, msg.BidID.OrderID(),
types.BidOpen, func(cbid types.Bid) bool {
ms.keepers.Market.OnBidLost(ctx, cbid) // ⇢ set state to BidLost
// Immediately close the escrow account for the lost bid
if err = ms.keepers.Escrow.AccountClose(ctx,
cbid.ID.ToEscrowAccountID()); err != nil {
return true // stop iteration on error
}
return false
})
The OnBidLost function (lines 93-98 in keeper.go) sets bid.State = types.BidLost using the same updateBid helper as the winning path. This ensures that failed bids release their locked funds immediately through Escrow.AccountClose.
Key Implementation Files
Understanding bid matching and lease creation requires familiarity with these core files in the akash-network/node repository:
x/market/keeper/keeper.go– Core state-transition helpers includingOnOrderMatched,OnBidMatched,OnBidLost, andCreateLease.x/market/handler/server.go– gRPC message server that orchestrates the lease creation transaction flow.x/market/keeper/keys– Key encoding utilities for theIndexedMapstructures managing order, bid, and lease prefixes.upgrades/software/v1.2.0/market.go– Migration logic for transitioning legacy KV-store data to the currentcollections.IndexedMapschema.
Summary
- Atomic Execution: The
CreateLeasehandler performs validation, escrow creation, lease storage, and state transitions in a single transaction that rolls back completely on any failure. - State Machines: Orders transition from
OpentoActiveviaOnOrderMatched, while winning bids move fromOpentoActiveviaOnBidMatchedand losing bids move toBidLostviaOnBidLost. - Escrow Management: The system creates a payment escrow for the winning lease via
Escrow.PaymentCreatewhile closing escrow accounts for all losing bids viaEscrow.AccountClose. - Data Integrity: All state changes utilize
collections.IndexedMapto ensure secondary indexes remain synchronized with primary storage.
Frequently Asked Questions
What triggers the bid matching process in Akash?
The bid matching process initiates when a deployment owner submits a MsgCreateLease transaction referencing a specific bid ID. This message triggers the CreateLease handler in x/market/handler/server.go, which validates the bid against the order and executes the matching logic if all conditions are met.
How does Akash ensure losing bids do not retain locked funds?
After creating the winning lease, the handler iterates through all remaining BidOpen states for the order using WithBidsForOrder. For each losing bid, it calls OnBidLost to update the state and immediately invokes Escrow.AccountClose to release the provider's locked collateral, ensuring no funds remain trapped in failed bids.
What happens if the escrow payment creation fails during lease creation?
If Escrow.PaymentCreate returns an error during the CreateLease execution, the transaction aborts immediately and returns the error to the caller. Because Cosmos SDK transactions are atomic, any state changes made earlier in the function are discarded, leaving the order and bid in their original Open state.
Where is the lease record actually stored during the matching process?
The lease record is persisted via ms.keepers.Market.CreateLease(ctx, bid) within the CreateLease handler. This method stores the lease object in the keeper's IndexedMap structure, making it queryable by lease ID while maintaining indexes for efficient provider and tenant lookups.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →