diff --git a/x/auction/abci.go b/x/auction/abci.go index 8ce80f90..402c5c12 100644 --- a/x/auction/abci.go +++ b/x/auction/abci.go @@ -6,17 +6,8 @@ import ( // EndBlocker runs at the end of every block. func EndBlocker(ctx sdk.Context, k Keeper) { - - var expiredAuctions []uint64 - k.IterateAuctionsByTime(ctx, ctx.BlockTime(), func(id uint64) bool { - expiredAuctions = append(expiredAuctions, id) - return false - }) - // Note: iteration and auction closing are in separate loops as db should not be modified during iteration // TODO is this correct? gov modifies during iteration - for _, id := range expiredAuctions { - err := k.CloseAuction(ctx, id) - if err != nil { - panic(err) - } + err := k.CloseExpiredAuctions(ctx) + if err != nil { + panic(err) } } diff --git a/x/auction/abci_test.go b/x/auction/abci_test.go index 418ca49a..4ee5cd13 100644 --- a/x/auction/abci_test.go +++ b/x/auction/abci_test.go @@ -22,7 +22,6 @@ func TestKeeper_EndBlocker(t *testing.T) { returnAddrs := addrs[1:] returnWeights := []sdk.Int{sdk.NewInt(1)} sellerModName := liquidator.ModuleName - //sellerAddr := supply.NewModuleAddress(sellerModName) tApp := app.NewTestApp() sellerAcc := supply.NewEmptyModuleAccount(sellerModName) diff --git a/x/auction/keeper/auctions.go b/x/auction/keeper/auctions.go index 8c92f3ba..755027fe 100644 --- a/x/auction/keeper/auctions.go +++ b/x/auction/keeper/auctions.go @@ -11,15 +11,18 @@ import ( // StartSurplusAuction starts a new surplus (forward) auction. func (k Keeper) StartSurplusAuction(ctx sdk.Context, seller string, lot sdk.Coin, bidDenom string) (uint64, sdk.Error) { - // create auction - auction := types.NewSurplusAuction(seller, lot, bidDenom, ctx.BlockTime().Add(types.DefaultMaxAuctionDuration)) - // take coins from module account + auction := types.NewSurplusAuction( + seller, + lot, + bidDenom, + ctx.BlockTime().Add(k.GetParams(ctx).MaxAuctionDuration)) + err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot)) if err != nil { return 0, err } - // store the auction + auctionID, err := k.StoreNewAuction(ctx, auction) if err != nil { return 0, err @@ -29,15 +32,19 @@ func (k Keeper) StartSurplusAuction(ctx sdk.Context, seller string, lot sdk.Coin // StartDebtAuction starts a new debt (reverse) auction. func (k Keeper) StartDebtAuction(ctx sdk.Context, buyer string, bid sdk.Coin, initialLot sdk.Coin) (uint64, sdk.Error) { - // create auction - auction := types.NewDebtAuction(buyer, bid, initialLot, ctx.BlockTime().Add(types.DefaultMaxAuctionDuration)) + + auction := types.NewDebtAuction( + buyer, + bid, + initialLot, + ctx.BlockTime().Add(k.GetParams(ctx).MaxAuctionDuration)) // This auction type mints coins at close. Need to check module account has minting privileges to avoid potential err in endblocker. macc := k.supplyKeeper.GetModuleAccount(ctx, buyer) if !macc.HasPermission(supply.Minter) { return 0, sdk.ErrInternal("module does not have minting permissions") } - // store the auction + auctionID, err := k.StoreNewAuction(ctx, auction) if err != nil { return 0, err @@ -45,21 +52,20 @@ func (k Keeper) StartDebtAuction(ctx sdk.Context, buyer string, bid sdk.Coin, in return auctionID, nil } -// StartCollateralAuction starts a new collateral (2-phase) auction where bidders bid up to a maxBid, then switch to bidding down on the Lot. +// StartCollateralAuction starts a new collateral (2-phase) auction. func (k Keeper) StartCollateralAuction(ctx sdk.Context, seller string, lot sdk.Coin, maxBid sdk.Coin, lotReturnAddrs []sdk.AccAddress, lotReturnWeights []sdk.Int) (uint64, sdk.Error) { - // create auction + weightedAddresses, err := types.NewWeightedAddresses(lotReturnAddrs, lotReturnWeights) if err != nil { return 0, err } auction := types.NewCollateralAuction(seller, lot, ctx.BlockTime().Add(types.DefaultMaxAuctionDuration), maxBid, weightedAddresses) - // take coins from module account err = k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot)) if err != nil { return 0, err } - // store the auction + auctionID, err := k.StoreNewAuction(ctx, auction) if err != nil { return 0, err @@ -70,18 +76,17 @@ func (k Keeper) StartCollateralAuction(ctx sdk.Context, seller string, lot sdk.C // PlaceBid places a bid on any auction. func (k Keeper) PlaceBid(ctx sdk.Context, auctionID uint64, bidder sdk.AccAddress, newAmount sdk.Coin) sdk.Error { - // get auction from store auction, found := k.GetAuction(ctx, auctionID) if !found { return sdk.ErrInternal("auction doesn't exist") } - // validate + // validation common to all auctions if ctx.BlockTime().After(auction.GetEndTime()) { return sdk.ErrInternal("auction has closed") } - // place bid + // move coins and return updated auction var err sdk.Error var updatedAuction types.Auction switch a := auction.(type) { @@ -106,14 +111,13 @@ func (k Keeper) PlaceBid(ctx sdk.Context, auctionID uint64, bidder sdk.AccAddres panic(fmt.Sprintf("unrecognized auction type: %T", auction)) } - // store updated auction k.SetAuction(ctx, updatedAuction) return nil } // PlaceBidSurplus places a forward bid on a surplus auction, moving coins and returning the updated auction. func (k Keeper) PlaceBidSurplus(ctx sdk.Context, a types.SurplusAuction, bidder sdk.AccAddress, bid sdk.Coin) (types.SurplusAuction, sdk.Error) { - // Validate New Bid + // Validate new bid if bid.Denom != a.Bid.Denom { return a, sdk.ErrInternal("bid denom doesn't match auction") } @@ -121,9 +125,9 @@ func (k Keeper) PlaceBidSurplus(ctx sdk.Context, a types.SurplusAuction, bidder return a, sdk.ErrInternal("bid not greater than last bid") } - // Move Coins - if !bidder.Equals(a.Bidder) && !a.Bid.IsZero() { // catch edge case of someone updating their bid with a low balance, also don't send if amt is zero - // pay back previous bidder + // New bidder pays back old bidder + // Catch edge cases of a bidder replacing their own bid, and the amount being zero (sending zero coins produces meaningless send events). + if !bidder.Equals(a.Bidder) && !a.Bid.IsZero() { err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, bidder, types.ModuleName, sdk.NewCoins(a.Bid)) if err != nil { return a, err @@ -133,7 +137,7 @@ func (k Keeper) PlaceBidSurplus(ctx sdk.Context, a types.SurplusAuction, bidder return a, err } } - // burn increase in bid + // Increase in bid is burned err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, bidder, a.Initiator, sdk.NewCoins(bid.Sub(a.Bid))) if err != nil { return a, err @@ -146,8 +150,7 @@ func (k Keeper) PlaceBidSurplus(ctx sdk.Context, a types.SurplusAuction, bidder // Update Auction a.Bidder = bidder a.Bid = bid - // increment timeout - a.EndTime = earliestTime(ctx.BlockTime().Add(types.DefaultBidDuration), a.MaxEndTime) + a.EndTime = earliestTime(ctx.BlockTime().Add(k.GetParams(ctx).BidDuration), a.MaxEndTime) // increment timeout return a, nil } @@ -167,9 +170,10 @@ func (k Keeper) PlaceForwardBidCollateral(ctx sdk.Context, a types.CollateralAuc if a.MaxBid.IsLT(bid) { return a, sdk.ErrInternal("bid higher than max bid") } - // Move Coins - // pay back previous bidder - if !bidder.Equals(a.Bidder) && !a.Bid.IsZero() { // catch edge case of someone updating their bid with a low balance, also don't send if amt is zero + + // New bidder pays back old bidder + // Catch edge cases of a bidder replacing their own bid, and the amount being zero (sending zero coins produces meaningless send events). + if !bidder.Equals(a.Bidder) && !a.Bid.IsZero() { err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, bidder, types.ModuleName, sdk.NewCoins(a.Bid)) if err != nil { return a, err @@ -179,7 +183,7 @@ func (k Keeper) PlaceForwardBidCollateral(ctx sdk.Context, a types.CollateralAuc return a, err } } - // pay increase in bid to auction initiator + // Increase in bid sent to auction initiator err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, bidder, a.Initiator, sdk.NewCoins(bid.Sub(a.Bid))) if err != nil { return a, err @@ -188,15 +192,14 @@ func (k Keeper) PlaceForwardBidCollateral(ctx sdk.Context, a types.CollateralAuc // Update Auction a.Bidder = bidder a.Bid = bid - // increment timeout - a.EndTime = earliestTime(ctx.BlockTime().Add(types.DefaultBidDuration), a.MaxEndTime) + a.EndTime = earliestTime(ctx.BlockTime().Add(k.GetParams(ctx).BidDuration), a.MaxEndTime) // increment timeout return a, nil } // PlaceReverseBidCollateral places a reverse bid on a collateral auction, moving coins and returning the updated auction. func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuction, bidder sdk.AccAddress, lot sdk.Coin) (types.CollateralAuction, sdk.Error) { - // Validate bid + // Validate new bid if lot.Denom != a.Lot.Denom { return a, sdk.ErrInternal("lot denom doesn't match auction") } @@ -210,8 +213,9 @@ func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuc return a, sdk.ErrInternal("auction in reverse phase, new bid not less than previous amount") } - // Move Coins - if !bidder.Equals(a.Bidder) { // catch edge case of someone updating their bid with a low balance + // New bidder pays back old bidder + // Catch edge cases of a bidder replacing their own bid + if !bidder.Equals(a.Bidder) { err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, bidder, types.ModuleName, sdk.NewCoins(a.Bid)) if err != nil { return a, err @@ -221,7 +225,8 @@ func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuc return a, err } } - // FIXME paying out rateably to cdp depositors is vulnerable to errors compounding over multiple bids + // Decrease in lot is sent to weighted addresses (normally the CDP depositors) + // TODO paying out rateably to cdp depositors is vulnerable to errors compounding over multiple bids - check this can't be gamed. lotPayouts, err := splitCoinIntoWeightedBuckets(a.Lot.Sub(lot), a.LotReturns.Weights) if err != nil { return a, err @@ -236,15 +241,14 @@ func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuc // Update Auction a.Bidder = bidder a.Lot = lot - // increment timeout - a.EndTime = earliestTime(ctx.BlockTime().Add(types.DefaultBidDuration), a.MaxEndTime) + a.EndTime = earliestTime(ctx.BlockTime().Add(k.GetParams(ctx).BidDuration), a.MaxEndTime) // increment timeout return a, nil } // PlaceBidDebt places a reverse bid on a debt auction, moving coins and returning the updated auction. func (k Keeper) PlaceBidDebt(ctx sdk.Context, a types.DebtAuction, bidder sdk.AccAddress, lot sdk.Coin) (types.DebtAuction, sdk.Error) { - // Validate New Bid + // Validate new bid if lot.Denom != a.Lot.Denom { return a, sdk.ErrInternal("lot denom doesn't match auction") } @@ -255,8 +259,9 @@ func (k Keeper) PlaceBidDebt(ctx sdk.Context, a types.DebtAuction, bidder sdk.Ac return a, sdk.ErrInternal("lot not smaller than last lot") } - // Move Coins - if !bidder.Equals(a.Bidder) { // catch edge case of someone updating their bid with a low balance + // New bidder pays back old bidder + // Catch edge cases of a bidder replacing their own bid + if !bidder.Equals(a.Bidder) { err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, bidder, types.ModuleName, sdk.NewCoins(a.Bid)) if err != nil { return a, err @@ -270,8 +275,7 @@ func (k Keeper) PlaceBidDebt(ctx sdk.Context, a types.DebtAuction, bidder sdk.Ac // Update Auction a.Bidder = bidder a.Lot = lot - // increment timeout - a.EndTime = earliestTime(ctx.BlockTime().Add(types.DefaultBidDuration), a.MaxEndTime) + a.EndTime = earliestTime(ctx.BlockTime().Add(k.GetParams(ctx).BidDuration), a.MaxEndTime) // increment timeout return a, nil } @@ -279,12 +283,11 @@ func (k Keeper) PlaceBidDebt(ctx sdk.Context, a types.DebtAuction, bidder sdk.Ac // CloseAuction closes an auction and distributes funds to the highest bidder. func (k Keeper) CloseAuction(ctx sdk.Context, auctionID uint64) sdk.Error { - // get the auction from the store auction, found := k.GetAuction(ctx, auctionID) if !found { return sdk.ErrInternal("auction doesn't exist") } - // error if auction has not reached the end time + if ctx.BlockTime().Before(auction.GetEndTime()) { return sdk.ErrInternal(fmt.Sprintf("auction can't be closed as curent block time (%v) is under auction end time (%v)", ctx.BlockTime(), auction.GetEndTime())) } @@ -342,6 +345,22 @@ func (k Keeper) PayoutCollateralAuction(ctx sdk.Context, a types.CollateralAucti return nil } +// CloseExpiredAuctions finds all auctions that are past (or at) their ending times and closes them, paying out to the highest bidder. +func (k Keeper) CloseExpiredAuctions(ctx sdk.Context) sdk.Error { + var expiredAuctions []uint64 + k.IterateAuctionsByTime(ctx, ctx.BlockTime(), func(id uint64) bool { + expiredAuctions = append(expiredAuctions, id) + return false + }) + // Note: iteration and auction closing are in separate loops as db should not be modified during iteration // TODO is this correct? gov modifies during iteration + for _, id := range expiredAuctions { + if err := k.CloseAuction(ctx, id); err != nil { + return err + } + } + return nil +} + // earliestTime returns the earliest of two times. func earliestTime(t1, t2 time.Time) time.Time { if t1.Before(t2) { diff --git a/x/auction/keeper/keeper.go b/x/auction/keeper/keeper.go index d756463f..c9ee241b 100644 --- a/x/auction/keeper/keeper.go +++ b/x/auction/keeper/keeper.go @@ -1,12 +1,14 @@ package keeper import ( + "fmt" "time" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/params/subspace" + "github.com/tendermint/tendermint/libs/log" "github.com/kava-labs/kava/x/auction/types" ) @@ -29,6 +31,11 @@ func NewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, supplyKeeper types.Suppl } } +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + // SetNextAuctionID stores an ID to be used for the next created auction func (k Keeper) SetNextAuctionID(ctx sdk.Context, id uint64) { store := ctx.KVStore(k.storeKey) @@ -79,16 +86,14 @@ func (k Keeper) SetAuction(ctx sdk.Context, auction types.Auction) { // remove the auction from the byTime index if it is already in there existingAuction, found := k.GetAuction(ctx, auction.GetID()) if found { - k.removeFromIndex(ctx, existingAuction.GetEndTime(), existingAuction.GetID()) + k.removeFromByTimeIndex(ctx, existingAuction.GetEndTime(), existingAuction.GetID()) } - // store auction store := prefix.NewStore(ctx.KVStore(k.storeKey), types.AuctionKeyPrefix) bz := k.cdc.MustMarshalBinaryLengthPrefixed(auction) store.Set(types.GetAuctionKey(auction.GetID()), bz) - // add to index - k.insertIntoIndex(ctx, auction.GetEndTime(), auction.GetID()) + k.InsertIntoByTimeIndex(ctx, auction.GetEndTime(), auction.GetID()) } // GetAuction gets an auction from the store. @@ -107,25 +112,23 @@ func (k Keeper) GetAuction(ctx sdk.Context, auctionID uint64) (types.Auction, bo // DeleteAuction removes an auction from the store, and any indexes. func (k Keeper) DeleteAuction(ctx sdk.Context, auctionID uint64) { - // remove from index auction, found := k.GetAuction(ctx, auctionID) if found { - k.removeFromIndex(ctx, auction.GetEndTime(), auctionID) + k.removeFromByTimeIndex(ctx, auction.GetEndTime(), auctionID) } - // delete auction store := prefix.NewStore(ctx.KVStore(k.storeKey), types.AuctionKeyPrefix) store.Delete(types.GetAuctionKey(auctionID)) } -// insertIntoIndex adds an auction ID and end time into the byTime index. -func (k Keeper) insertIntoIndex(ctx sdk.Context, endTime time.Time, auctionID uint64) { +// InsertIntoByTimeIndex adds an auction ID and end time into the byTime index. +func (k Keeper) InsertIntoByTimeIndex(ctx sdk.Context, endTime time.Time, auctionID uint64) { // TODO make private, and find way to make tests work store := prefix.NewStore(ctx.KVStore(k.storeKey), types.AuctionByTimeKeyPrefix) store.Set(types.GetAuctionByTimeKey(endTime, auctionID), types.Uint64ToBytes(auctionID)) } -// removeFromIndex removes an auction ID and end time from the byTime index. -func (k Keeper) removeFromIndex(ctx sdk.Context, endTime time.Time, auctionID uint64) { +// removeFromByTimeIndex removes an auction ID and end time from the byTime index. +func (k Keeper) removeFromByTimeIndex(ctx sdk.Context, endTime time.Time, auctionID uint64) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.AuctionByTimeKeyPrefix) store.Delete(types.GetAuctionByTimeKey(endTime, auctionID)) } diff --git a/x/auction/keeper/keeper_test.go b/x/auction/keeper/keeper_test.go index 3c59d9ae..03adaeeb 100644 --- a/x/auction/keeper/keeper_test.go +++ b/x/auction/keeper/keeper_test.go @@ -113,7 +113,7 @@ func TestIterateAuctionsByTime(t *testing.T) { {time.Date(9999, time.January, 1, 0, 0, 0, 0, time.UTC), 0}, // distant future } for _, v := range byTimeIndex { - keeper.InsertIntoIndex(ctx, v.endTime, v.auctionID) + keeper.InsertIntoByTimeIndex(ctx, v.endTime, v.auctionID) } // read out values from index up to a cutoff time and check they are as expected diff --git a/x/auction/types/auctions.go b/x/auction/types/auctions.go index 9fbd01cd..1db5036e 100644 --- a/x/auction/types/auctions.go +++ b/x/auction/types/auctions.go @@ -46,7 +46,8 @@ func (a BaseAuction) String() string { ) } -// SurplusAuction is a forward auction that burns what it receives as bids. +// SurplusAuction is a forward auction that burns what it receives from bids. +// It is normally used to sell off excess pegged asset acquired by the CDP system. type SurplusAuction struct { BaseAuction } @@ -69,6 +70,7 @@ func NewSurplusAuction(seller string, lot sdk.Coin, bidDenom string, endTime tim } // DebtAuction is a reverse auction that mints what it pays out. +// It is normally used to acquire pegged asset to cover the CDP system's debts that were not covered by selling collateral. type DebtAuction struct { BaseAuction } @@ -86,7 +88,7 @@ func NewDebtAuction(buyerModAccName string, bid sdk.Coin, initialLot sdk.Coin, E Initiator: buyerModAccName, Lot: initialLot, Bidder: supply.NewModuleAddress(buyerModAccName), // send proceeds from the first bid to the buyer. - Bid: bid, // amount that the buyer it buying - doesn't change over course of auction + Bid: bid, // amount that the buyer is buying - doesn't change over course of auction EndTime: EndTime, MaxEndTime: EndTime, }} @@ -95,8 +97,9 @@ func NewDebtAuction(buyerModAccName string, bid sdk.Coin, initialLot sdk.Coin, E // CollateralAuction is a two phase auction. // Initially, in forward auction phase, bids can be placed up to a max bid. -// Then it switches to a reverse auction phase, where the initial amount up for auction is bidded down. +// Then it switches to a reverse auction phase, where the initial amount up for auction is bid down. // Unsold Lot is sent to LotReturns, being divided among the addresses by weight. +// Collateral auctions are normally used to sell off collateral seized from CDPs. type CollateralAuction struct { BaseAuction MaxBid sdk.Coin diff --git a/x/auction/types/auctions_test.go b/x/auction/types/auctions_test.go deleted file mode 100644 index a4d059d6..00000000 --- a/x/auction/types/auctions_test.go +++ /dev/null @@ -1,396 +0,0 @@ -package types - -// // TODO can this be less verbose? Should PlaceBid() be split into smaller functions? -// // It would be possible to combine all auction tests into one test runner. -// func TesSurplusAuction_PlaceBid(t *testing.T) { -// seller := sdk.AccAddress([]byte("a_seller")) -// buyer1 := sdk.AccAddress([]byte("buyer1")) -// buyer2 := sdk.AccAddress([]byte("buyer2")) -// end := EndTime(10000) -// now := EndTime(10) - -// type args struct { -// currentBlockHeight EndTime -// bidder sdk.AccAddress -// lot sdk.Coin -// bid sdk.Coin -// } -// tests := []struct { -// name string -// auction SurplusAuction -// args args -// expectedOutputs []BankOutput -// expectedInputs []BankInput -// expectedEndTime EndTime -// expectedBidder sdk.AccAddress -// expectedBid sdk.Coin -// expectpass bool -// }{ -// { -// "normal", -// SurplusAuction{BaseAuction{ -// Initiator: seller, -// Lot: c("usdx", 100), -// Bidder: buyer1, -// Bid: c("kava", 6), -// EndTime: end, -// MaxEndTime: end, -// }}, -// args{now, buyer2, c("usdx", 100), c("kava", 10)}, -// []BankOutput{{buyer2, c("kava", 10)}}, -// []BankInput{{buyer1, c("kava", 6)}, {seller, c("kava", 4)}}, -// now + DefaultMaxBidDuration, -// buyer2, -// c("kava", 10), -// true, -// }, -// { -// "lowBid", -// SurplusAuction{BaseAuction{ -// Initiator: seller, -// Lot: c("usdx", 100), -// Bidder: buyer1, -// Bid: c("kava", 6), -// EndTime: end, -// MaxEndTime: end, -// }}, -// args{now, buyer2, c("usdx", 100), c("kava", 5)}, -// []BankOutput{}, -// []BankInput{}, -// end, -// buyer1, -// c("kava", 6), -// false, -// }, -// { -// "equalBid", -// SurplusAuction{BaseAuction{ -// Initiator: seller, -// Lot: c("usdx", 100), -// Bidder: buyer1, -// Bid: c("kava", 6), -// EndTime: end, -// MaxEndTime: end, -// }}, -// args{now, buyer2, c("usdx", 100), c("kava", 6)}, -// []BankOutput{}, -// []BankInput{}, -// end, -// buyer1, -// c("kava", 6), -// false, -// }, -// { -// "timeout", -// SurplusAuction{BaseAuction{ -// Initiator: seller, -// Lot: c("usdx", 100), -// Bidder: buyer1, -// Bid: c("kava", 6), -// EndTime: end, -// MaxEndTime: end, -// }}, -// args{end + 1, buyer2, c("usdx", 100), c("kava", 10)}, -// []BankOutput{}, -// []BankInput{}, -// end, -// buyer1, -// c("kava", 6), -// false, -// }, -// { -// "hitMaxEndTime", -// SurplusAuction{BaseAuction{ -// Initiator: seller, -// Lot: c("usdx", 100), -// Bidder: buyer1, -// Bid: c("kava", 6), -// EndTime: end, -// MaxEndTime: end, -// }}, -// args{end - 1, buyer2, c("usdx", 100), c("kava", 10)}, -// []BankOutput{{buyer2, c("kava", 10)}}, -// []BankInput{{buyer1, c("kava", 6)}, {seller, c("kava", 4)}}, -// end, // end time should be capped at MaxEndTime -// buyer2, -// c("kava", 10), -// true, -// }, -// } -// for _, tc := range tests { -// t.Run(tc.name, func(t *testing.T) { -// // update auction and return in/outputs -// outputs, inputs, err := tc.auction.PlaceBid(tc.args.currentBlockHeight, tc.args.bidder, tc.args.lot, tc.args.bid) - -// // check for err -// if tc.expectpass { -// require.Nil(t, err) -// } else { -// require.NotNil(t, err) -// } -// // check for correct in/outputs -// require.Equal(t, tc.expectedOutputs, outputs) -// require.Equal(t, tc.expectedInputs, inputs) -// // check for correct EndTime, bidder, bid -// require.Equal(t, tc.expectedEndTime, tc.auction.EndTime) -// require.Equal(t, tc.expectedBidder, tc.auction.Bidder) -// require.Equal(t, tc.expectedBid, tc.auction.Bid) -// }) -// } -// } - -// func TestDebtAuction_PlaceBid(t *testing.T) { -// buyer := sdk.AccAddress([]byte("a_buyer")) -// seller1 := sdk.AccAddress([]byte("seller1")) -// seller2 := sdk.AccAddress([]byte("seller2")) -// end := EndTime(10000) -// now := EndTime(10) - -// type args struct { -// currentBlockHeight EndTime -// bidder sdk.AccAddress -// lot sdk.Coin -// bid sdk.Coin -// } -// tests := []struct { -// name string -// auction DebtAuction -// args args -// expectedOutputs []BankOutput -// expectedInputs []BankInput -// expectedEndTime EndTime -// expectedBidder sdk.AccAddress -// expectedLot sdk.Coin -// expectpass bool -// }{ -// { -// "normal", -// DebtAuction{BaseAuction{ -// Initiator: buyer, -// Lot: c("kava", 10), -// Bidder: seller1, -// Bid: c("usdx", 100), -// EndTime: end, -// MaxEndTime: end, -// }}, -// args{now, seller2, c("kava", 9), c("usdx", 100)}, -// []BankOutput{{seller2, c("usdx", 100)}}, -// []BankInput{{seller1, c("usdx", 100)}, {buyer, c("kava", 1)}}, -// now + DefaultMaxBidDuration, -// seller2, -// c("kava", 9), -// true, -// }, -// { -// "highBid", -// DebtAuction{BaseAuction{ -// Initiator: buyer, -// Lot: c("kava", 10), -// Bidder: seller1, -// Bid: c("usdx", 100), -// EndTime: end, -// MaxEndTime: end, -// }}, -// args{now, seller2, c("kava", 11), c("usdx", 100)}, -// []BankOutput{}, -// []BankInput{}, -// end, -// seller1, -// c("kava", 10), -// false, -// }, -// { -// "equalBid", -// DebtAuction{BaseAuction{ -// Initiator: buyer, -// Lot: c("kava", 10), -// Bidder: seller1, -// Bid: c("usdx", 100), -// EndTime: end, -// MaxEndTime: end, -// }}, -// args{now, seller2, c("kava", 10), c("usdx", 100)}, -// []BankOutput{}, -// []BankInput{}, -// end, -// seller1, -// c("kava", 10), -// false, -// }, -// { -// "timeout", -// DebtAuction{BaseAuction{ -// Initiator: buyer, -// Lot: c("kava", 10), -// Bidder: seller1, -// Bid: c("usdx", 100), -// EndTime: end, -// MaxEndTime: end, -// }}, -// args{end + 1, seller2, c("kava", 9), c("usdx", 100)}, -// []BankOutput{}, -// []BankInput{}, -// end, -// seller1, -// c("kava", 10), -// false, -// }, -// { -// "hitMaxEndTime", -// DebtAuction{BaseAuction{ -// Initiator: buyer, -// Lot: c("kava", 10), -// Bidder: seller1, -// Bid: c("usdx", 100), -// EndTime: end, -// MaxEndTime: end, -// }}, -// args{end - 1, seller2, c("kava", 9), c("usdx", 100)}, -// []BankOutput{{seller2, c("usdx", 100)}}, -// []BankInput{{seller1, c("usdx", 100)}, {buyer, c("kava", 1)}}, -// end, // end time should be capped at MaxEndTime -// seller2, -// c("kava", 9), -// true, -// }, -// } -// for _, tc := range tests { -// t.Run(tc.name, func(t *testing.T) { -// // update auction and return in/outputs -// outputs, inputs, err := tc.auction.PlaceBid(tc.args.currentBlockHeight, tc.args.bidder, tc.args.lot, tc.args.bid) - -// // check for err -// if tc.expectpass { -// require.Nil(t, err) -// } else { -// require.NotNil(t, err) -// } -// // check for correct in/outputs -// require.Equal(t, tc.expectedOutputs, outputs) -// require.Equal(t, tc.expectedInputs, inputs) -// // check for correct EndTime, bidder, bid -// require.Equal(t, tc.expectedEndTime, tc.auction.EndTime) -// require.Equal(t, tc.expectedBidder, tc.auction.Bidder) -// require.Equal(t, tc.expectedLot, tc.auction.Lot) -// }) -// } -// } - -// func TestCollateralAuction_PlaceBid(t *testing.T) { -// cdpOwner := sdk.AccAddress([]byte("a_cdp_owner")) -// seller := sdk.AccAddress([]byte("a_seller")) -// buyer1 := sdk.AccAddress([]byte("buyer1")) -// buyer2 := sdk.AccAddress([]byte("buyer2")) -// end := EndTime(10000) -// now := EndTime(10) - -// type args struct { -// currentBlockHeight EndTime -// bidder sdk.AccAddress -// lot sdk.Coin -// bid sdk.Coin -// } -// tests := []struct { -// name string -// auction CollateralAuction -// args args -// expectedOutputs []BankOutput -// expectedInputs []BankInput -// expectedEndTime EndTime -// expectedBidder sdk.AccAddress -// expectedLot sdk.Coin -// expectedBid sdk.Coin -// expectpass bool -// }{ -// { -// "normalForwardBid", -// CollateralAuction{BaseAuction: BaseAuction{ -// Initiator: seller, -// Lot: c("xrp", 100), -// Bidder: buyer1, -// Bid: c("usdx", 5), -// EndTime: end, -// MaxEndTime: end}, -// MaxBid: c("usdx", 10), -// OtherPerson: cdpOwner, -// }, -// args{now, buyer2, c("xrp", 100), c("usdx", 6)}, -// []BankOutput{{buyer2, c("usdx", 6)}}, -// []BankInput{{buyer1, c("usdx", 5)}, {seller, c("usdx", 1)}}, -// now + DefaultMaxBidDuration, -// buyer2, -// c("xrp", 100), -// c("usdx", 6), -// true, -// }, -// { -// "normalSwitchOverBid", -// CollateralAuction{BaseAuction: BaseAuction{ -// Initiator: seller, -// Lot: c("xrp", 100), -// Bidder: buyer1, -// Bid: c("usdx", 5), -// EndTime: end, -// MaxEndTime: end}, -// MaxBid: c("usdx", 10), -// OtherPerson: cdpOwner, -// }, -// args{now, buyer2, c("xrp", 99), c("usdx", 10)}, -// []BankOutput{{buyer2, c("usdx", 10)}}, -// []BankInput{{buyer1, c("usdx", 5)}, {seller, c("usdx", 5)}, {cdpOwner, c("xrp", 1)}}, -// now + DefaultMaxBidDuration, -// buyer2, -// c("xrp", 99), -// c("usdx", 10), -// true, -// }, -// { -// "normalDebtBid", -// CollateralAuction{BaseAuction: BaseAuction{ -// Initiator: seller, -// Lot: c("xrp", 99), -// Bidder: buyer1, -// Bid: c("usdx", 10), -// EndTime: end, -// MaxEndTime: end}, -// MaxBid: c("usdx", 10), -// OtherPerson: cdpOwner, -// }, -// args{now, buyer2, c("xrp", 90), c("usdx", 10)}, -// []BankOutput{{buyer2, c("usdx", 10)}}, -// []BankInput{{buyer1, c("usdx", 10)}, {cdpOwner, c("xrp", 9)}}, -// now + DefaultMaxBidDuration, -// buyer2, -// c("xrp", 90), -// c("usdx", 10), -// true, -// }, -// // TODO more test cases -// } -// for _, tc := range tests { -// t.Run(tc.name, func(t *testing.T) { -// // update auction and return in/outputs -// outputs, inputs, err := tc.auction.PlaceBid(tc.args.currentBlockHeight, tc.args.bidder, tc.args.lot, tc.args.bid) - -// // check for err -// if tc.expectpass { -// require.Nil(t, err) -// } else { -// require.NotNil(t, err) -// } -// // check for correct in/outputs -// require.Equal(t, tc.expectedOutputs, outputs) -// require.Equal(t, tc.expectedInputs, inputs) -// // check for correct EndTime, bidder, bid -// require.Equal(t, tc.expectedEndTime, tc.auction.EndTime) -// require.Equal(t, tc.expectedBidder, tc.auction.Bidder) -// require.Equal(t, tc.expectedLot, tc.auction.Lot) -// require.Equal(t, tc.expectedBid, tc.auction.Bid) -// }) -// } -// } - -// // defined to avoid cluttering test cases with long function name -// func c(denom string, amount int64) sdk.Coin { -// return sdk.NewInt64Coin(denom, amount) -// } diff --git a/x/auction/types/keys.go b/x/auction/types/keys.go index 78ce6f34..aca635a9 100644 --- a/x/auction/types/keys.go +++ b/x/auction/types/keys.go @@ -21,7 +21,6 @@ const ( DefaultParamspace = ModuleName ) -// TODO use cont to keep immutability? var ( AuctionKeyPrefix = []byte{0x00} // prefix for keys that store auctions AuctionByTimeKeyPrefix = []byte{0x01} // prefix for keys that are part of the auctionsByTime index @@ -37,14 +36,14 @@ func GetAuctionByTimeKey(endTime time.Time, auctionID uint64) []byte { return append(sdk.FormatTimeBytes(endTime), Uint64ToBytes(auctionID)...) } -// Uint64FromBytes converts some fixed length bytes back into a uint64. -func Uint64FromBytes(bz []byte) uint64 { - return binary.BigEndian.Uint64(bz) -} - // Uint64ToBytes converts a uint64 into fixed length bytes for use in store keys. func Uint64ToBytes(id uint64) []byte { bz := make([]byte, 8) binary.BigEndian.PutUint64(bz, uint64(id)) return bz } + +// Uint64FromBytes converts some fixed length bytes back into a uint64. +func Uint64FromBytes(bz []byte) uint64 { + return binary.BigEndian.Uint64(bz) +}