From 94e4d9459b74cb45bcb6fb0f22df48da79c92063 Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Fri, 13 Sep 2024 13:00:34 +0530 Subject: [PATCH] Add method to pick service provider auction winner --- x/auction/keeper/keeper.go | 136 +++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/x/auction/keeper/keeper.go b/x/auction/keeper/keeper.go index 4b506d53f..f7d04017e 100644 --- a/x/auction/keeper/keeper.go +++ b/x/auction/keeper/keeper.go @@ -795,3 +795,139 @@ func (k Keeper) pickAuctionWinner(ctx sdk.Context, auction *auctiontypes.Auction return nil } + +// Pick winner for service_provider auction +func (k Keeper) pickServiceProviderAuctionWinner(ctx sdk.Context, auction *auctiontypes.Auction) error { + k.Logger(ctx).Info(fmt.Sprintf("Picking auction %s winners.", auction.Id)) + + bids, err := k.GetBids(ctx, auction.Id) + if err != nil { + return err + } + + var revealedBids []*auctiontypes.Bid + for _, bid := range bids { + k.Logger(ctx).Info(fmt.Sprintf("Processing bid %s %s", bid.BidderAddress, bid.BidAmount.String())) + + // Only consider revealed bids. + if bid.Status != auctiontypes.BidStatusRevealed { + k.Logger(ctx).Info(fmt.Sprintf("Ignoring unrevealed bid %s %s", bid.BidderAddress, bid.BidAmount.String())) + continue + } + + revealedBids = append(revealedBids, bid) + } + + // Sort the valid bids + slices.SortFunc(revealedBids, func(a, b *auctiontypes.Bid) int { + if a.BidAmount.Amount.LT(b.BidAmount.Amount) { + return -1 + } else if a.BidAmount.Amount.GT(b.BidAmount.Amount) { + return 1 + } + return 0 + }) + + numWinners := int(auction.NumProviders) + if len(revealedBids) < numWinners { + numWinners = (len(revealedBids)) + } + winnerBids := revealedBids[:numWinners] + + auction.Status = auctiontypes.AuctionStatusCompleted + + if len(winnerBids) > 0 { + winnerAddresses := make([]string, len(winnerBids)) + winningBids := make([]types.Coin, len(winnerBids)) + for i, bid := range winnerBids { + winnerAddresses[i] = bid.BidderAddress + winningBids[i] = bid.BidAmount + } + auction.WinnerAddresses = winnerAddresses + auction.WinningBids = winningBids + auction.WinningPrice = winnerBids[0].BidAmount + + if len(winnerBids) > 0 { + // The last best bid is the winning price + auction.WinningPrice = winnerBids[len(winnerBids)-1].BidAmount + } + for _, bid := range winnerBids { + k.Logger(ctx).Info(fmt.Sprintf("Auction %s winner address: %s, bid amount: %s.", auction.Id, bid.BidderAddress, bid.BidAmount.String())) + } + k.Logger(ctx).Info(fmt.Sprintf("Auction %s winner price %s.", auction.Id, auction.WinningPrice.String())) + } else { + k.Logger(ctx).Info(fmt.Sprintf("Auction %s has no valid revealed bids (no winner).", auction.Id)) + } + + if err := k.SaveAuction(ctx, auction); err != nil { + return err + } + + for _, bid := range bids { + bidderAddress, err := sdk.AccAddressFromBech32(bid.BidderAddress) + if err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Invalid bidderAddress address. %v", err)) + panic("Invalid bidder address.") + } + + if bid.Status == auctiontypes.BidStatusRevealed { + // Send reveal fee back to bidders that've revealed the bid. + sdkErr := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, auctiontypes.ModuleName, bidderAddress, sdk.NewCoins(bid.RevealFee)) + if sdkErr != nil { + k.Logger(ctx).Error(fmt.Sprintf("Auction error returning reveal fee: %v", sdkErr)) + panic(sdkErr) + } + } + } + + // Process winner account (if nobody bids, there won't be a winner). + if len(winnerBids) > 0 { + winnerAddresses := make([]string, len(winnerBids)) + for i, bid := range winnerBids { + winnerAddresses[i] = bid.BidderAddress + winnerAddress, err := sdk.AccAddressFromBech32(bid.BidderAddress) + if err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Invalid winner address. %v", err)) + panic("Invalid winner address.") + } + + // Send winning price to bidders + sdkErrWinner := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, auctiontypes.ModuleName, winnerAddress, sdk.NewCoins(auction.WinningPrice)) + if sdkErrWinner != nil { + k.Logger(ctx).Error(fmt.Sprintf("Auction error sending funds to winner: %v", sdkErrWinner)) + panic(sdkErrWinner) + } + + // Send back extra amount to auction creator + totalMaxBidAmount := auction.MaxPrice.Amount.MulRaw(int64(auction.NumProviders)) + totalAmountPaid := auction.WinningPrice.Amount.Mul(math.NewInt(int64(auction.NumProviders))) + + extraAmountCoin := sdk.NewCoin(auction.MaxPrice.Denom, totalMaxBidAmount.Sub(totalAmountPaid)) + + sdkErrCreator := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, auctiontypes.ModuleName, sdk.AccAddress(auction.OwnerAddress), sdk.NewCoins(extraAmountCoin)) + if sdkErrCreator != nil { + k.Logger(ctx).Error(fmt.Sprintf("Auction error returning bid amount: %v", sdkErrCreator)) + panic(sdkErrCreator) + } + } + } else { + sdkErr := k.bankKeeper.SendCoinsFromModuleToAccount( + ctx, + auctiontypes.ModuleName, + sdk.AccAddress(auction.OwnerAddress), + sdk.NewCoins(auction.MaxPrice)) + if sdkErr != nil { + k.Logger(ctx).Error(fmt.Sprintf("Auction error returning bid amount: %v", sdkErr)) + panic(sdkErr) + } + } + + // Notify other modules (hook). + k.Logger(ctx).Info(fmt.Sprintf("Auction %s notifying %d modules.", auction.Id, len(k.usageKeepers))) + for _, keeper := range k.usageKeepers { + k.Logger(ctx).Info(fmt.Sprintf("Auction %s notifying module %s.", auction.Id, keeper.ModuleName())) + keeper.OnAuctionWinnerSelected(ctx, auction.Id) + } + + return nil +}