mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-11-04 06:37:26 +00:00 
			
		
		
		
	Add min bid increments (#380)
* refactor bidding test * add some more bid test cases * add balance checks to bid tests * add more checks to bid tests * add min bid increments * protect against negative lot amounts * fix params tests * change endblocker to beginblocker * update spec * fix params tests * fix: update alias Co-authored-by: Kevin Davis <karzak@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									e72b20eb7d
								
							
						
					
					
						commit
						7eede47769
					
				@ -271,9 +271,10 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
 | 
			
		||||
	// During begin block slashing happens after distr.BeginBlocker so that
 | 
			
		||||
	// there is nothing left over in the validator fee pool, so as to keep the
 | 
			
		||||
	// CanWithdrawInvariant invariant.
 | 
			
		||||
	app.mm.SetOrderBeginBlockers(mint.ModuleName, distr.ModuleName, slashing.ModuleName, validatorvesting.ModuleName, cdp.ModuleName)
 | 
			
		||||
	// Auction.BeginBlocker will close out expired auctions and pay debt back to cdp. So it should be run before cdp.BeginBlocker which cancels out debt with stable and starts more auctions.
 | 
			
		||||
	app.mm.SetOrderBeginBlockers(mint.ModuleName, distr.ModuleName, slashing.ModuleName, validatorvesting.ModuleName, auction.ModuleName, cdp.ModuleName)
 | 
			
		||||
 | 
			
		||||
	app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName, pricefeed.ModuleName, auction.ModuleName)
 | 
			
		||||
	app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName, pricefeed.ModuleName)
 | 
			
		||||
 | 
			
		||||
	// Note: genutils must occur after staking so that pools are properly
 | 
			
		||||
	// initialized with tokens from genesis accounts.
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,8 @@ import (
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// EndBlocker runs at the end of every block.
 | 
			
		||||
func EndBlocker(ctx sdk.Context, k Keeper) {
 | 
			
		||||
// BeginBlocker runs at the start of every block.
 | 
			
		||||
func BeginBlocker(ctx sdk.Context, k Keeper) {
 | 
			
		||||
	err := k.CloseExpiredAuctions(ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@ import (
 | 
			
		||||
	"github.com/kava-labs/kava/x/cdp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestKeeper_EndBlocker(t *testing.T) {
 | 
			
		||||
func TestKeeper_BeginBlocker(t *testing.T) {
 | 
			
		||||
	// Setup
 | 
			
		||||
	_, addrs := app.GeneratePrivKeyAddressPairs(2)
 | 
			
		||||
	buyer := addrs[0]
 | 
			
		||||
@ -36,13 +36,14 @@ func TestKeeper_EndBlocker(t *testing.T) {
 | 
			
		||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
			
		||||
	keeper := tApp.GetAuctionKeeper()
 | 
			
		||||
 | 
			
		||||
	// Start an auction and place a bid
 | 
			
		||||
	auctionID, err := keeper.StartCollateralAuction(ctx, sellerModName, c("token1", 20), c("token2", 50), returnAddrs, returnWeights, c("debt", 40))
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	require.NoError(t, keeper.PlaceBid(ctx, auctionID, buyer, c("token2", 30)))
 | 
			
		||||
 | 
			
		||||
	// Run the endblocker, simulating a block time 1ns before auction expiry
 | 
			
		||||
	// Run the beginblocker, simulating a block time 1ns before auction expiry
 | 
			
		||||
	preExpiryTime := ctx.BlockTime().Add(auction.DefaultBidDuration - 1)
 | 
			
		||||
	auction.EndBlocker(ctx.WithBlockTime(preExpiryTime), keeper)
 | 
			
		||||
	auction.BeginBlocker(ctx.WithBlockTime(preExpiryTime), keeper)
 | 
			
		||||
 | 
			
		||||
	// Check auction has not been closed yet
 | 
			
		||||
	_, found := keeper.GetAuction(ctx, auctionID)
 | 
			
		||||
@ -50,7 +51,7 @@ func TestKeeper_EndBlocker(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	// Run the endblocker, simulating a block time equal to auction expiry
 | 
			
		||||
	expiryTime := ctx.BlockTime().Add(auction.DefaultBidDuration)
 | 
			
		||||
	auction.EndBlocker(ctx.WithBlockTime(expiryTime), keeper)
 | 
			
		||||
	auction.BeginBlocker(ctx.WithBlockTime(expiryTime), keeper)
 | 
			
		||||
 | 
			
		||||
	// Check auction has been closed
 | 
			
		||||
	_, found = keeper.GetAuction(ctx, auctionID)
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
// nolint
 | 
			
		||||
// autogenerated code using github.com/rigelrozanski/multitool
 | 
			
		||||
// aliases generated for the following subdirectories:
 | 
			
		||||
// ALIASGEN: github.com/kava-labs/kava/x/auction/types/
 | 
			
		||||
// ALIASGEN: github.com/kava-labs/kava/x/auction/keeper/
 | 
			
		||||
// ALIASGEN: github.com/kava-labs/kava/x/auction/keeper
 | 
			
		||||
// ALIASGEN: github.com/kava-labs/kava/x/auction/types
 | 
			
		||||
package auction
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
@ -13,6 +13,7 @@ import (
 | 
			
		||||
const (
 | 
			
		||||
	DefaultCodespace                      = types.DefaultCodespace
 | 
			
		||||
	CodeInvalidInitialAuctionID           = types.CodeInvalidInitialAuctionID
 | 
			
		||||
	CodeInvalidModulePermissions          = types.CodeInvalidModulePermissions
 | 
			
		||||
	CodeUnrecognizedAuctionType           = types.CodeUnrecognizedAuctionType
 | 
			
		||||
	CodeAuctionNotFound                   = types.CodeAuctionNotFound
 | 
			
		||||
	CodeAuctionHasNotExpired              = types.CodeAuctionHasNotExpired
 | 
			
		||||
@ -21,60 +22,101 @@ const (
 | 
			
		||||
	CodeInvalidLotDenom                   = types.CodeInvalidLotDenom
 | 
			
		||||
	CodeBidTooSmall                       = types.CodeBidTooSmall
 | 
			
		||||
	CodeBidTooLarge                       = types.CodeBidTooLarge
 | 
			
		||||
	CodeLotTooSmall                       = types.CodeLotTooSmall
 | 
			
		||||
	CodeLotTooLarge                       = types.CodeLotTooLarge
 | 
			
		||||
	CodeCollateralAuctionIsInReversePhase = types.CodeCollateralAuctionIsInReversePhase
 | 
			
		||||
	CodeCollateralAuctionIsInForwardPhase = types.CodeCollateralAuctionIsInForwardPhase
 | 
			
		||||
	EventTypeAuctionStart                 = types.EventTypeAuctionStart
 | 
			
		||||
	EventTypeAuctionBid                   = types.EventTypeAuctionBid
 | 
			
		||||
	EventTypeAuctionClose                 = types.EventTypeAuctionClose
 | 
			
		||||
	AttributeValueCategory                = types.AttributeValueCategory
 | 
			
		||||
	AttributeKeyAuctionID                 = types.AttributeKeyAuctionID
 | 
			
		||||
	AttributeKeyAuctionType               = types.AttributeKeyAuctionType
 | 
			
		||||
	AttributeKeyBidder                    = types.AttributeKeyBidder
 | 
			
		||||
	AttributeKeyBidDenom                  = types.AttributeKeyBidDenom
 | 
			
		||||
	AttributeKeyLotDenom                  = types.AttributeKeyLotDenom
 | 
			
		||||
	AttributeKeyBidAmount                 = types.AttributeKeyBidAmount
 | 
			
		||||
	AttributeKeyLotAmount                 = types.AttributeKeyLotAmount
 | 
			
		||||
	AttributeKeyEndTime                   = types.AttributeKeyEndTime
 | 
			
		||||
	DefaultNextAuctionID                  = types.DefaultNextAuctionID
 | 
			
		||||
	ModuleName                            = types.ModuleName
 | 
			
		||||
	StoreKey                              = types.StoreKey
 | 
			
		||||
	RouterKey                             = types.RouterKey
 | 
			
		||||
	DefaultParamspace                     = types.DefaultParamspace
 | 
			
		||||
	QuerierRoute                          = types.QuerierRoute
 | 
			
		||||
	DefaultMaxAuctionDuration             = types.DefaultMaxAuctionDuration
 | 
			
		||||
	DefaultBidDuration                    = types.DefaultBidDuration
 | 
			
		||||
	QueryGetAuction                       = types.QueryGetAuction
 | 
			
		||||
	DefaultNextAuctionID                  = types.DefaultNextAuctionID
 | 
			
		||||
	QueryGetAuctions                      = types.QueryGetAuctions
 | 
			
		||||
	QueryGetParams                        = types.QueryGetParams
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// functions aliases
 | 
			
		||||
	NewKeeper                            = keeper.NewKeeper
 | 
			
		||||
	NewQuerier                           = keeper.NewQuerier
 | 
			
		||||
	NewSurplusAuction                    = types.NewSurplusAuction
 | 
			
		||||
	NewDebtAuction                       = types.NewDebtAuction
 | 
			
		||||
	NewCollateralAuction                 = types.NewCollateralAuction
 | 
			
		||||
	NewWeightedAddresses                 = types.NewWeightedAddresses
 | 
			
		||||
	RegisterCodec                        = types.RegisterCodec
 | 
			
		||||
	ErrInvalidInitialAuctionID           = types.ErrInvalidInitialAuctionID
 | 
			
		||||
	ErrInvalidModulePermissions          = types.ErrInvalidModulePermissions
 | 
			
		||||
	ErrUnrecognizedAuctionType           = types.ErrUnrecognizedAuctionType
 | 
			
		||||
	ErrAuctionNotFound                   = types.ErrAuctionNotFound
 | 
			
		||||
	ErrAuctionHasNotExpired              = types.ErrAuctionHasNotExpired
 | 
			
		||||
	ErrAuctionHasExpired                 = types.ErrAuctionHasExpired
 | 
			
		||||
	ErrInvalidBidDenom                   = types.ErrInvalidBidDenom
 | 
			
		||||
	ErrInvalidLotDenom                   = types.ErrInvalidLotDenom
 | 
			
		||||
	ErrBidTooSmall                       = types.ErrBidTooSmall
 | 
			
		||||
	ErrBidTooLarge                       = types.ErrBidTooLarge
 | 
			
		||||
	ErrLotTooSmall                       = types.ErrLotTooSmall
 | 
			
		||||
	ErrLotTooLarge                       = types.ErrLotTooLarge
 | 
			
		||||
	ErrCollateralAuctionIsInReversePhase = types.ErrCollateralAuctionIsInReversePhase
 | 
			
		||||
	ErrCollateralAuctionIsInForwardPhase = types.ErrCollateralAuctionIsInForwardPhase
 | 
			
		||||
	NewGenesisState                      = types.NewGenesisState
 | 
			
		||||
	DefaultGenesisState                  = types.DefaultGenesisState
 | 
			
		||||
	GetAuctionKey                        = types.GetAuctionKey
 | 
			
		||||
	GetAuctionByTimeKey                  = types.GetAuctionByTimeKey
 | 
			
		||||
	Uint64FromBytes      = types.Uint64FromBytes
 | 
			
		||||
	Uint64ToBytes                        = types.Uint64ToBytes
 | 
			
		||||
	Uint64FromBytes                      = types.Uint64FromBytes
 | 
			
		||||
	NewMsgPlaceBid                       = types.NewMsgPlaceBid
 | 
			
		||||
	NewParams                            = types.NewParams
 | 
			
		||||
	DefaultParams                        = types.DefaultParams
 | 
			
		||||
	ParamKeyTable                        = types.ParamKeyTable
 | 
			
		||||
	NewKeeper            = keeper.NewKeeper
 | 
			
		||||
	NewQuerier           = keeper.NewQuerier
 | 
			
		||||
	NewQueryAllAuctionParams             = types.NewQueryAllAuctionParams
 | 
			
		||||
	NewAuctionWithPhase                  = types.NewAuctionWithPhase
 | 
			
		||||
 | 
			
		||||
	// variable aliases
 | 
			
		||||
	DistantFuture          = types.DistantFuture
 | 
			
		||||
	ModuleCdc              = types.ModuleCdc
 | 
			
		||||
	AuctionKeyPrefix       = types.AuctionKeyPrefix
 | 
			
		||||
	AuctionByTimeKeyPrefix = types.AuctionByTimeKeyPrefix
 | 
			
		||||
	NextAuctionIDKey       = types.NextAuctionIDKey
 | 
			
		||||
	KeyAuctionBidDuration  = types.KeyAuctionBidDuration
 | 
			
		||||
	KeyAuctionDuration     = types.KeyAuctionDuration
 | 
			
		||||
	DefaultIncrement       = types.DefaultIncrement
 | 
			
		||||
	KeyBidDuration         = types.KeyBidDuration
 | 
			
		||||
	KeyMaxAuctionDuration  = types.KeyMaxAuctionDuration
 | 
			
		||||
	KeyIncrementSurplus    = types.KeyIncrementSurplus
 | 
			
		||||
	KeyIncrementDebt       = types.KeyIncrementDebt
 | 
			
		||||
	KeyIncrementCollateral = types.KeyIncrementCollateral
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	Keeper                = keeper.Keeper
 | 
			
		||||
	Auction               = types.Auction
 | 
			
		||||
	Auctions              = types.Auctions
 | 
			
		||||
	BaseAuction           = types.BaseAuction
 | 
			
		||||
	SurplusAuction        = types.SurplusAuction
 | 
			
		||||
	DebtAuction           = types.DebtAuction
 | 
			
		||||
	CollateralAuction     = types.CollateralAuction
 | 
			
		||||
	WeightedAddresses     = types.WeightedAddresses
 | 
			
		||||
	SupplyKeeper          = types.SupplyKeeper
 | 
			
		||||
	GenesisAuctions   = types.GenesisAuctions
 | 
			
		||||
	GenesisAuction        = types.GenesisAuction
 | 
			
		||||
	GenesisAuctions       = types.GenesisAuctions
 | 
			
		||||
	GenesisState          = types.GenesisState
 | 
			
		||||
	MsgPlaceBid           = types.MsgPlaceBid
 | 
			
		||||
	Params                = types.Params
 | 
			
		||||
	Keeper            = keeper.Keeper
 | 
			
		||||
	QueryAuctionParams    = types.QueryAuctionParams
 | 
			
		||||
	QueryAllAuctionParams = types.QueryAllAuctionParams
 | 
			
		||||
	AuctionWithPhase      = types.AuctionWithPhase
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -168,8 +168,14 @@ func (k Keeper) PlaceBidSurplus(ctx sdk.Context, a types.SurplusAuction, bidder
 | 
			
		||||
	if bid.Denom != a.Bid.Denom {
 | 
			
		||||
		return a, types.ErrInvalidBidDenom(k.codespace, bid.Denom, a.Bid.Denom)
 | 
			
		||||
	}
 | 
			
		||||
	if !a.Bid.IsLT(bid) {
 | 
			
		||||
		return a, types.ErrBidTooSmall(k.codespace, bid, a.Bid)
 | 
			
		||||
	minNewBidAmt := a.Bid.Amount.Add( // new bids must be some % greater than old bid, and at least 1 larger to avoid replacing an old bid at no cost
 | 
			
		||||
		sdk.MaxInt(
 | 
			
		||||
			sdk.NewInt(1),
 | 
			
		||||
			sdk.NewDecFromInt(a.Bid.Amount).Mul(k.GetParams(ctx).IncrementSurplus).RoundInt(),
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	if bid.Amount.LT(minNewBidAmt) {
 | 
			
		||||
		return a, types.ErrBidTooSmall(k.codespace, bid, sdk.NewCoin(a.Bid.Denom, minNewBidAmt))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// New bidder pays back old bidder
 | 
			
		||||
@ -225,8 +231,15 @@ func (k Keeper) PlaceForwardBidCollateral(ctx sdk.Context, a types.CollateralAuc
 | 
			
		||||
	if a.IsReversePhase() {
 | 
			
		||||
		return a, types.ErrCollateralAuctionIsInReversePhase(k.codespace, a.ID)
 | 
			
		||||
	}
 | 
			
		||||
	if !a.Bid.IsLT(bid) {
 | 
			
		||||
		return a, types.ErrBidTooSmall(k.codespace, bid, a.Bid)
 | 
			
		||||
	minNewBidAmt := a.Bid.Amount.Add( // new bids must be some % greater than old bid, and at least 1 larger to avoid replacing an old bid at no cost
 | 
			
		||||
		sdk.MaxInt(
 | 
			
		||||
			sdk.NewInt(1),
 | 
			
		||||
			sdk.NewDecFromInt(a.Bid.Amount).Mul(k.GetParams(ctx).IncrementCollateral).RoundInt(),
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	minNewBidAmt = sdk.MinInt(minNewBidAmt, a.MaxBid.Amount) // allow new bids to hit MaxBid even though it may be less than the increment %
 | 
			
		||||
	if bid.Amount.LT(minNewBidAmt) {
 | 
			
		||||
		return a, types.ErrBidTooSmall(k.codespace, bid, sdk.NewCoin(a.Bid.Denom, minNewBidAmt))
 | 
			
		||||
	}
 | 
			
		||||
	if a.MaxBid.IsLT(bid) {
 | 
			
		||||
		return a, types.ErrBidTooLarge(k.codespace, bid, a.MaxBid)
 | 
			
		||||
@ -294,8 +307,17 @@ func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuc
 | 
			
		||||
	if !a.IsReversePhase() {
 | 
			
		||||
		return a, types.ErrCollateralAuctionIsInForwardPhase(k.codespace, a.ID)
 | 
			
		||||
	}
 | 
			
		||||
	if !lot.IsLT(a.Lot) {
 | 
			
		||||
		return a, types.ErrLotTooLarge(k.codespace, lot, a.Lot)
 | 
			
		||||
	maxNewLotAmt := a.Lot.Amount.Sub( // new lot must be some % less than old lot, and at least 1 smaller to avoid replacing an old bid at no cost
 | 
			
		||||
		sdk.MaxInt(
 | 
			
		||||
			sdk.NewInt(1),
 | 
			
		||||
			sdk.NewDecFromInt(a.Lot.Amount).Mul(k.GetParams(ctx).IncrementCollateral).RoundInt(),
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	if lot.Amount.GT(maxNewLotAmt) {
 | 
			
		||||
		return a, types.ErrLotTooLarge(k.codespace, lot, sdk.NewCoin(a.Lot.Denom, maxNewLotAmt))
 | 
			
		||||
	}
 | 
			
		||||
	if lot.IsNegative() {
 | 
			
		||||
		return a, types.ErrLotTooSmall(k.codespace, lot, sdk.NewCoin(a.Lot.Denom, sdk.ZeroInt()))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// New bidder pays back old bidder
 | 
			
		||||
@ -351,8 +373,17 @@ func (k Keeper) PlaceBidDebt(ctx sdk.Context, a types.DebtAuction, bidder sdk.Ac
 | 
			
		||||
	if lot.Denom != a.Lot.Denom {
 | 
			
		||||
		return a, types.ErrInvalidLotDenom(k.codespace, lot.Denom, a.Lot.Denom)
 | 
			
		||||
	}
 | 
			
		||||
	if !lot.IsLT(a.Lot) {
 | 
			
		||||
		return a, types.ErrLotTooLarge(k.codespace, lot, a.Lot)
 | 
			
		||||
	maxNewLotAmt := a.Lot.Amount.Sub( // new lot must be some % less than old lot, and at least 1 smaller to avoid replacing an old bid at no cost
 | 
			
		||||
		sdk.MaxInt(
 | 
			
		||||
			sdk.NewInt(1),
 | 
			
		||||
			sdk.NewDecFromInt(a.Lot.Amount).Mul(k.GetParams(ctx).IncrementDebt).RoundInt(),
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	if lot.Amount.GT(maxNewLotAmt) {
 | 
			
		||||
		return a, types.ErrLotTooLarge(k.codespace, lot, sdk.NewCoin(a.Lot.Denom, maxNewLotAmt))
 | 
			
		||||
	}
 | 
			
		||||
	if lot.IsNegative() {
 | 
			
		||||
		return a, types.ErrLotTooSmall(k.codespace, lot, sdk.NewCoin(a.Lot.Denom, sdk.ZeroInt()))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// New bidder pays back old bidder
 | 
			
		||||
 | 
			
		||||
@ -22,8 +22,7 @@ const (
 | 
			
		||||
	Invalid    AuctionType = 0
 | 
			
		||||
	Surplus    AuctionType = 1
 | 
			
		||||
	Debt       AuctionType = 2
 | 
			
		||||
	CollateralPhase1 AuctionType = 3
 | 
			
		||||
	CollateralPhase2 AuctionType = 4
 | 
			
		||||
	Collateral AuctionType = 3
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
@ -49,12 +48,12 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
	type bidArgs struct {
 | 
			
		||||
		bidder sdk.AccAddress
 | 
			
		||||
		amount sdk.Coin
 | 
			
		||||
		secondBidder sdk.AccAddress
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name            string
 | 
			
		||||
		auctionArgs     auctionArgs
 | 
			
		||||
		setupBids       []bidArgs
 | 
			
		||||
		bidArgs         bidArgs
 | 
			
		||||
		expectedError   sdk.CodeType
 | 
			
		||||
		expectedEndTime time.Time
 | 
			
		||||
@ -65,17 +64,30 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
		{
 | 
			
		||||
			"basic: auction doesn't exist",
 | 
			
		||||
			auctionArgs{Surplus, "", c("token1", 1), c("token2", 1), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			bidArgs{buyer, c("token2", 10), nil},
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("token2", 10)},
 | 
			
		||||
			types.CodeAuctionNotFound,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
			c("token2", 10),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"basic: closed auction",
 | 
			
		||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("token2", 10)},
 | 
			
		||||
			types.CodeAuctionHasExpired,
 | 
			
		||||
			types.DistantFuture,
 | 
			
		||||
			nil,
 | 
			
		||||
			c("token2", 0),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"surplus: normal",
 | 
			
		||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			bidArgs{buyer, c("token2", 10), nil},
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("token2", 10)},
 | 
			
		||||
			sdk.CodeType(0),
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
@ -85,7 +97,8 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
		{
 | 
			
		||||
			"surplus: second bidder",
 | 
			
		||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			bidArgs{buyer, c("token2", 10), secondBuyer},
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 10)}},
 | 
			
		||||
			bidArgs{secondBuyer, c("token2", 11)},
 | 
			
		||||
			sdk.CodeType(0),
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			secondBuyer,
 | 
			
		||||
@ -95,27 +108,52 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
		{
 | 
			
		||||
			"surplus: invalid bid denom",
 | 
			
		||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			bidArgs{buyer, c("badtoken", 10), nil},
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("badtoken", 10)},
 | 
			
		||||
			types.CodeInvalidBidDenom,
 | 
			
		||||
			types.DistantFuture,
 | 
			
		||||
			nil, // surplus auctions are created with initial bidder as a nil address
 | 
			
		||||
			c("token2", 0),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"surplus: invalid bid (less than)",
 | 
			
		||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 100)}},
 | 
			
		||||
			bidArgs{buyer, c("token2", 99)},
 | 
			
		||||
			types.CodeBidTooSmall,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
			c("token2", 10),
 | 
			
		||||
			c("token2", 100),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"surplus: invalid bid (equal)",
 | 
			
		||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			bidArgs{buyer, c("token2", 0), nil},
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("token2", 0)}, // min bid is technically 0 at default 5%, but it's capped at 1
 | 
			
		||||
			types.CodeBidTooSmall,
 | 
			
		||||
			types.DistantFuture,
 | 
			
		||||
			nil, // surplus auctions are created with initial bidder as a nil address
 | 
			
		||||
			c("token2", 0),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"surplus: invalid bid (less than min increment)",
 | 
			
		||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 100)}},
 | 
			
		||||
			bidArgs{buyer, c("token2", 104)}, // min bid is 105 at default 5%
 | 
			
		||||
			types.CodeBidTooSmall,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
			c("token2", 10),
 | 
			
		||||
			c("token2", 100),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"debt: normal",
 | 
			
		||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 20), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
 | 
			
		||||
			bidArgs{buyer, c("token1", 10), nil},
 | 
			
		||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("token1", 10)},
 | 
			
		||||
			sdk.CodeType(0),
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
@ -124,8 +162,9 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"debt: second bidder",
 | 
			
		||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 20), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
 | 
			
		||||
			bidArgs{buyer, c("token1", 10), secondBuyer},
 | 
			
		||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
 | 
			
		||||
			[]bidArgs{{buyer, c("token1", 10)}},
 | 
			
		||||
			bidArgs{secondBuyer, c("token1", 9)},
 | 
			
		||||
			sdk.CodeType(0),
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			secondBuyer,
 | 
			
		||||
@ -134,28 +173,53 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"debt: invalid lot denom",
 | 
			
		||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 20), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
 | 
			
		||||
			bidArgs{buyer, c("badtoken", 10), nil},
 | 
			
		||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("badtoken", 10)},
 | 
			
		||||
			types.CodeInvalidLotDenom,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
			c("token1", 20),
 | 
			
		||||
			types.DistantFuture,
 | 
			
		||||
			supply.NewModuleAddress(modName),
 | 
			
		||||
			c("token2", 100),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"debt: invalid lot size (larger)",
 | 
			
		||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 20), []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			bidArgs{buyer, c("token1", 21), nil},
 | 
			
		||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("token1", 21)},
 | 
			
		||||
			types.CodeLotTooLarge,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
			c("token1", 20),
 | 
			
		||||
			types.DistantFuture,
 | 
			
		||||
			supply.NewModuleAddress(modName),
 | 
			
		||||
			c("token2", 100),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"debt: invalid lot size (equal)",
 | 
			
		||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("token1", 20)},
 | 
			
		||||
			types.CodeLotTooLarge,
 | 
			
		||||
			types.DistantFuture,
 | 
			
		||||
			supply.NewModuleAddress(modName),
 | 
			
		||||
			c("token2", 100),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"debt: invalid lot size (larger than min increment)",
 | 
			
		||||
			auctionArgs{Debt, modName, c("token1", 60), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("token1", 58)}, // max lot at default 5% is 57
 | 
			
		||||
			types.CodeLotTooLarge,
 | 
			
		||||
			types.DistantFuture,
 | 
			
		||||
			supply.NewModuleAddress(modName),
 | 
			
		||||
			c("token2", 100),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [forward]: normal",
 | 
			
		||||
			auctionArgs{CollateralPhase1, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			bidArgs{buyer, c("token2", 10), nil},
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("token2", 10)},
 | 
			
		||||
			sdk.CodeType(0),
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
@ -164,8 +228,9 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [forward]: second bidder",
 | 
			
		||||
			auctionArgs{CollateralPhase1, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			bidArgs{buyer, c("token2", 10), secondBuyer},
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 10)}},
 | 
			
		||||
			bidArgs{secondBuyer, c("token2", 11)},
 | 
			
		||||
			sdk.CodeType(0),
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			secondBuyer,
 | 
			
		||||
@ -174,18 +239,20 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [forward]: invalid bid denom",
 | 
			
		||||
			auctionArgs{CollateralPhase1, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			bidArgs{buyer, c("badtoken", 10), nil},
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("badtoken", 10)},
 | 
			
		||||
			types.CodeInvalidBidDenom,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
			c("token2", 10),
 | 
			
		||||
			types.DistantFuture,
 | 
			
		||||
			nil,
 | 
			
		||||
			c("token2", 0),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [forward]: invalid bid size (smaller)",
 | 
			
		||||
			auctionArgs{CollateralPhase1, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			bidArgs{buyer, c("token2", 0), nil},                                                                                          // lot, bid
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 10)}},
 | 
			
		||||
			bidArgs{buyer, c("token2", 9)},
 | 
			
		||||
			types.CodeBidTooSmall,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
@ -193,19 +260,54 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [forward]: invalid bid size (greater than max)",
 | 
			
		||||
			auctionArgs{CollateralPhase1, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			bidArgs{buyer, c("token2", 101), nil},                                                                                        // lot, bid
 | 
			
		||||
			types.CodeBidTooLarge,
 | 
			
		||||
			"collateral [forward]: invalid bid size (equal)",
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("token2", 0)},
 | 
			
		||||
			types.CodeBidTooSmall,
 | 
			
		||||
			types.DistantFuture,
 | 
			
		||||
			nil,
 | 
			
		||||
			c("token2", 0),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [forward]: invalid bid size (less than min increment)",
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 50)}},
 | 
			
		||||
			bidArgs{buyer, c("token2", 51)},
 | 
			
		||||
			types.CodeBidTooSmall,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
			c("token2", 10),
 | 
			
		||||
			c("token2", 50),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [forward]: less than min increment but equal to maxBid",
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 99)}},
 | 
			
		||||
			bidArgs{buyer, c("token2", 100)}, // min bid at default 5% is 104
 | 
			
		||||
			sdk.CodeType(0),
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
			c("token2", 100),
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [forward]: invalid bid size (greater than max)",
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			nil,
 | 
			
		||||
			bidArgs{buyer, c("token2", 101)},
 | 
			
		||||
			types.CodeBidTooLarge,
 | 
			
		||||
			types.DistantFuture,
 | 
			
		||||
			nil,
 | 
			
		||||
			c("token2", 0),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [reverse]: normal",
 | 
			
		||||
			auctionArgs{CollateralPhase2, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			bidArgs{buyer, c("token1", 15), nil},
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
 | 
			
		||||
			bidArgs{buyer, c("token1", 15)},
 | 
			
		||||
			sdk.CodeType(0),
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
@ -214,8 +316,9 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [reverse]: second bidder",
 | 
			
		||||
			auctionArgs{CollateralPhase2, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			bidArgs{buyer, c("token1", 15), secondBuyer},
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 50)}, {buyer, c("token1", 15)}},                                                         // put auction into reverse phase, and add a reverse phase bid
 | 
			
		||||
			bidArgs{secondBuyer, c("token1", 14)},
 | 
			
		||||
			sdk.CodeType(0),
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			secondBuyer,
 | 
			
		||||
@ -224,28 +327,20 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [reverse]: invalid lot denom",
 | 
			
		||||
			auctionArgs{CollateralPhase2, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			bidArgs{buyer, c("badtoken", 15), nil},
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
 | 
			
		||||
			bidArgs{buyer, c("badtoken", 15)},
 | 
			
		||||
			types.CodeInvalidLotDenom,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
			c("token2", 50),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [reverse]: invalid lot size (equal)",
 | 
			
		||||
			auctionArgs{CollateralPhase2, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			bidArgs{buyer, c("token1", 20), nil},
 | 
			
		||||
			types.CodeLotTooLarge,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
			c("token2", 50),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [reverse]: invalid lot size (greater)",
 | 
			
		||||
			auctionArgs{CollateralPhase2, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			bidArgs{buyer, c("token1", 21), nil},
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 50)}},                                                                                   // put auction into reverse phase
 | 
			
		||||
			bidArgs{buyer, c("token1", 21)},
 | 
			
		||||
			types.CodeLotTooLarge,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
@ -253,13 +348,25 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"basic: closed auction",
 | 
			
		||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
			
		||||
			bidArgs{buyer, c("token2", 10), nil},
 | 
			
		||||
			types.CodeAuctionHasExpired,
 | 
			
		||||
			"collateral [reverse]: invalid lot size (equal)",
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 50)}},                                                                                   // put auction into reverse phase
 | 
			
		||||
			bidArgs{buyer, c("token1", 20)},
 | 
			
		||||
			types.CodeLotTooLarge,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
			c("token2", 10),
 | 
			
		||||
			c("token2", 50),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"collateral [reverse]: invalid lot size (larger than min increment)",
 | 
			
		||||
			auctionArgs{Collateral, modName, c("token1", 60), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
			
		||||
			[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
 | 
			
		||||
			bidArgs{buyer, c("token1", 58)},     // max lot at default 5% is 57
 | 
			
		||||
			types.CodeLotTooLarge,
 | 
			
		||||
			someTime.Add(types.DefaultBidDuration),
 | 
			
		||||
			buyer,
 | 
			
		||||
			c("token2", 50),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
@ -283,6 +390,7 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
			)
 | 
			
		||||
			ctx := tApp.NewContext(false, abci.Header{})
 | 
			
		||||
			keeper := tApp.GetAuctionKeeper()
 | 
			
		||||
			bank := tApp.GetBankKeeper()
 | 
			
		||||
 | 
			
		||||
			// Start Auction
 | 
			
		||||
			var id uint64
 | 
			
		||||
@ -292,56 +400,84 @@ func TestAuctionBidding(t *testing.T) {
 | 
			
		||||
				id, _ = keeper.StartSurplusAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.lot, tc.auctionArgs.bid.Denom)
 | 
			
		||||
			case Debt:
 | 
			
		||||
				id, _ = keeper.StartDebtAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.bid, tc.auctionArgs.lot, tc.auctionArgs.debt)
 | 
			
		||||
			case CollateralPhase1, CollateralPhase2:
 | 
			
		||||
			case Collateral:
 | 
			
		||||
				id, _ = keeper.StartCollateralAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.lot, tc.auctionArgs.bid, tc.auctionArgs.addresses, tc.auctionArgs.weights, tc.auctionArgs.debt) // seller, lot, maxBid, otherPerson
 | 
			
		||||
				// Move CollateralAuction to debt phase by placing max bid
 | 
			
		||||
				if tc.auctionArgs.auctionType == CollateralPhase2 {
 | 
			
		||||
					err = keeper.PlaceBid(ctx, id, tc.bidArgs.bidder, tc.auctionArgs.bid)
 | 
			
		||||
					require.NoError(t, err)
 | 
			
		||||
				}
 | 
			
		||||
			default:
 | 
			
		||||
				t.Fail()
 | 
			
		||||
			}
 | 
			
		||||
			// Place setup bids
 | 
			
		||||
			for _, b := range tc.setupBids {
 | 
			
		||||
				require.NoError(t, keeper.PlaceBid(ctx, id, b.bidder, b.amount))
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Close the auction early to test late bidding (if applicable)
 | 
			
		||||
			if strings.Contains(tc.name, "closed") {
 | 
			
		||||
				ctx = ctx.WithBlockTime(types.DistantFuture.Add(1))
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Store some state for use in checks
 | 
			
		||||
			oldAuction, found := keeper.GetAuction(ctx, id)
 | 
			
		||||
			var oldBidder sdk.AccAddress
 | 
			
		||||
			if found {
 | 
			
		||||
				oldBidder = oldAuction.GetBidder()
 | 
			
		||||
			}
 | 
			
		||||
			oldBidderOldCoins := bank.GetCoins(ctx, oldBidder)
 | 
			
		||||
			newBidderOldCoins := bank.GetCoins(ctx, tc.bidArgs.bidder)
 | 
			
		||||
 | 
			
		||||
			// Place bid on auction
 | 
			
		||||
			err = keeper.PlaceBid(ctx, id, tc.bidArgs.bidder, tc.bidArgs.amount)
 | 
			
		||||
 | 
			
		||||
			// Place second bid from new bidder
 | 
			
		||||
			if tc.bidArgs.secondBidder != nil {
 | 
			
		||||
				// Set bid increase/decrease based on auction type, phase
 | 
			
		||||
				var secondBid sdk.Coin
 | 
			
		||||
				switch tc.auctionArgs.auctionType {
 | 
			
		||||
				case Surplus, CollateralPhase1:
 | 
			
		||||
					secondBid = tc.bidArgs.amount.Add(c(tc.bidArgs.amount.Denom, 1))
 | 
			
		||||
				case Debt, CollateralPhase2:
 | 
			
		||||
					secondBid = tc.bidArgs.amount.Sub(c(tc.bidArgs.amount.Denom, 1))
 | 
			
		||||
				default:
 | 
			
		||||
					t.Fail()
 | 
			
		||||
				}
 | 
			
		||||
				// Place the second bid
 | 
			
		||||
				err2 := keeper.PlaceBid(ctx, id, tc.bidArgs.secondBidder, secondBid)
 | 
			
		||||
				require.NoError(t, err2)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Check success/failure
 | 
			
		||||
			if tc.expectpass {
 | 
			
		||||
				require.Nil(t, err)
 | 
			
		||||
				// Get auction from store
 | 
			
		||||
				auction, found := keeper.GetAuction(ctx, id)
 | 
			
		||||
				// Check auction was found
 | 
			
		||||
				newAuction, found := keeper.GetAuction(ctx, id)
 | 
			
		||||
				require.True(t, found)
 | 
			
		||||
				// Check auction values
 | 
			
		||||
				require.Equal(t, modName, auction.GetInitiator())
 | 
			
		||||
				require.Equal(t, tc.expectedBidder, auction.GetBidder())
 | 
			
		||||
				require.Equal(t, tc.expectedBid, auction.GetBid())
 | 
			
		||||
				require.Equal(t, tc.expectedEndTime, auction.GetEndTime())
 | 
			
		||||
				require.Equal(t, modName, newAuction.GetInitiator())
 | 
			
		||||
				require.Equal(t, tc.expectedBidder, newAuction.GetBidder())
 | 
			
		||||
				require.Equal(t, tc.expectedBid, newAuction.GetBid())
 | 
			
		||||
				require.Equal(t, tc.expectedEndTime, newAuction.GetEndTime())
 | 
			
		||||
 | 
			
		||||
				// Check coins have moved between bidder and previous bidder
 | 
			
		||||
				bidAmt := tc.bidArgs.amount
 | 
			
		||||
				switch tc.auctionArgs.auctionType {
 | 
			
		||||
				case Debt:
 | 
			
		||||
					bidAmt = oldAuction.GetBid()
 | 
			
		||||
				case Collateral:
 | 
			
		||||
					collatAuction, _ := oldAuction.(types.CollateralAuction)
 | 
			
		||||
					if collatAuction.IsReversePhase() {
 | 
			
		||||
						bidAmt = oldAuction.GetBid()
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if oldBidder.Equals(tc.bidArgs.bidder) { // same bidder
 | 
			
		||||
					require.Equal(t, newBidderOldCoins.Sub(cs(bidAmt.Sub(oldAuction.GetBid()))), bank.GetCoins(ctx, tc.bidArgs.bidder))
 | 
			
		||||
				} else {
 | 
			
		||||
					require.Equal(t, cs(newBidderOldCoins.Sub(cs(bidAmt))...), bank.GetCoins(ctx, tc.bidArgs.bidder)) // wrapping in cs() to avoid comparing nil and empty coins
 | 
			
		||||
					if oldBidder.Equals(supply.NewModuleAddress(oldAuction.GetInitiator())) {                         // handle checking debt coins for case debt auction has had no bids placed yet TODO make this less confusing
 | 
			
		||||
						require.Equal(t, cs(oldBidderOldCoins.Add(cs(oldAuction.GetBid()))...).Add(cs(c("debt", oldAuction.GetBid().Amount.Int64()))), bank.GetCoins(ctx, oldBidder))
 | 
			
		||||
					} else {
 | 
			
		||||
						require.Equal(t, cs(oldBidderOldCoins.Add(cs(oldAuction.GetBid()))...), bank.GetCoins(ctx, oldBidder))
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			} else {
 | 
			
		||||
				// Check expected error code type
 | 
			
		||||
				require.NotNil(t, err, "PlaceBid did not return an error") // catch nil values before they cause a panic below
 | 
			
		||||
				require.Equal(t, tc.expectedError, err.Result().Code)
 | 
			
		||||
 | 
			
		||||
				// Check auction values
 | 
			
		||||
				newAuction, found := keeper.GetAuction(ctx, id)
 | 
			
		||||
				if found {
 | 
			
		||||
					require.Equal(t, modName, newAuction.GetInitiator())
 | 
			
		||||
					require.Equal(t, tc.expectedBidder, newAuction.GetBidder())
 | 
			
		||||
					require.Equal(t, tc.expectedBid, newAuction.GetBid())
 | 
			
		||||
					require.Equal(t, tc.expectedEndTime, newAuction.GetEndTime())
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Check coins have not moved
 | 
			
		||||
				require.Equal(t, newBidderOldCoins, bank.GetCoins(ctx, tc.bidArgs.bidder))
 | 
			
		||||
				require.Equal(t, oldBidderOldCoins, bank.GetCoins(ctx, oldBidder))
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -149,10 +149,11 @@ func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BeginBlock module begin-block
 | 
			
		||||
func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}
 | 
			
		||||
func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) {
 | 
			
		||||
	BeginBlocker(ctx, am.keeper)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EndBlock module end-block
 | 
			
		||||
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
 | 
			
		||||
	EndBlocker(ctx, am.keeper)
 | 
			
		||||
func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
 | 
			
		||||
	return []abci.ValidatorUpdate{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,9 @@
 | 
			
		||||
type Params struct {
 | 
			
		||||
	MaxAuctionDuration time.Duration `json:"max_auction_duration" yaml:"max_auction_duration"` // max length of auction
 | 
			
		||||
	MaxBidDuration     time.Duration `json:"max_bid_duration" yaml:"max_bid_duration"` // additional time added to the auction end time after each bid, capped by the expiry.
 | 
			
		||||
	IncrementSurplus    sdk.Dec       `json:"increment_surplus" yaml:"increment_surplus"`       // percentage change (of auc.Bid) required for a new bid on a surplus auction
 | 
			
		||||
	IncrementDebt       sdk.Dec       `json:"increment_debt" yaml:"increment_debt"`             // percentage change (of auc.Lot) required for a new bid on a debt auction
 | 
			
		||||
	IncrementCollateral sdk.Dec       `json:"increment_collateral" yaml:"increment_collateral"` // percentage change (of auc.Bid or auc.Lot) required for a new bid on a collateral auction
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,7 @@ The `x/auction` module emits the following events:
 | 
			
		||||
| message     | module        | auction            |
 | 
			
		||||
| message     | sender        | {sender address}   |
 | 
			
		||||
 | 
			
		||||
## EndBlock
 | 
			
		||||
## BeginBlock
 | 
			
		||||
 | 
			
		||||
| Type          | Attribute Key | Attribute Value |
 | 
			
		||||
|---------------|---------------|-----------------|
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,10 @@
 | 
			
		||||
 | 
			
		||||
The auction module contains the following parameters:
 | 
			
		||||
 | 
			
		||||
| Key                | Type                   | Example    |
 | 
			
		||||
| ------------------ | ---------------------- | -----------|
 | 
			
		||||
| MaxAuctionDuration | string (time.Duration) | "48h0m0s"  |
 | 
			
		||||
| BidDuration        | string (time.Duration) | "3h0m0s"   |
 | 
			
		||||
| Key                 | Type                   | Example                | Description                                                                           |
 | 
			
		||||
|---------------------|------------------------|------------------------|---------------------------------------------------------------------------------------|
 | 
			
		||||
| MaxAuctionDuration  | string (time.Duration) | "48h0m0s"              |                                                                                       |
 | 
			
		||||
| BidDuration         | string (time.Duration) | "3h0m0s"               |                                                                                       |
 | 
			
		||||
| IncrementSurplus    | string (dec)           | "0.050000000000000000" | percentage change in bid required for a new bid on a surplus auction                  |
 | 
			
		||||
| IncrementDebt       | string (dec)           | "0.050000000000000000" | percentage change in lot required for a new bid on a debt auction                     |
 | 
			
		||||
| IncrementCollateral | string (dec)           | "0.050000000000000000" | percentage change in either bid or lot required for a new bid on a collateral auction |
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
# End Block
 | 
			
		||||
# Begin Block
 | 
			
		||||
 | 
			
		||||
At the end of each block, auctions that have reached `EndTime` are closed. The logic to close auctions is as follows:
 | 
			
		||||
At the start of each block, auctions that have reached `EndTime` are closed. The logic to close auctions is as follows:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
var expiredAuctions []uint64
 | 
			
		||||
@ -6,7 +6,7 @@
 | 
			
		||||
3. **[Messages](03_messages.md)**
 | 
			
		||||
4. **[Events](04_events.md)**
 | 
			
		||||
5. **[Params](05_params.md)**
 | 
			
		||||
6. **[EndBlock](06_end_block.md)**
 | 
			
		||||
6. **[BeginBlock](06_begin_block.md)**
 | 
			
		||||
 | 
			
		||||
## Abstract
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -61,7 +61,7 @@ func (a BaseAuction) GetBid() sdk.Coin { return a.Bid }
 | 
			
		||||
// GetEndTime is a getter for auction end time.
 | 
			
		||||
func (a BaseAuction) GetEndTime() time.Time { return a.EndTime }
 | 
			
		||||
 | 
			
		||||
// GetType returns theauction type. Used to identify auctions in event attributes.
 | 
			
		||||
// GetType returns the auction type. Used to identify auctions in event attributes.
 | 
			
		||||
func (a BaseAuction) GetType() string { return "base" }
 | 
			
		||||
 | 
			
		||||
// Validate verifies that the auction end time is before max end time
 | 
			
		||||
 | 
			
		||||
@ -21,9 +21,10 @@ const (
 | 
			
		||||
	CodeInvalidLotDenom                   sdk.CodeType      = 8
 | 
			
		||||
	CodeBidTooSmall                       sdk.CodeType      = 9
 | 
			
		||||
	CodeBidTooLarge                       sdk.CodeType      = 10
 | 
			
		||||
	CodeLotTooLarge                       sdk.CodeType      = 11
 | 
			
		||||
	CodeCollateralAuctionIsInReversePhase sdk.CodeType      = 12
 | 
			
		||||
	CodeCollateralAuctionIsInForwardPhase sdk.CodeType      = 13
 | 
			
		||||
	CodeLotTooSmall                       sdk.CodeType      = 11
 | 
			
		||||
	CodeLotTooLarge                       sdk.CodeType      = 12
 | 
			
		||||
	CodeCollateralAuctionIsInReversePhase sdk.CodeType      = 13
 | 
			
		||||
	CodeCollateralAuctionIsInForwardPhase sdk.CodeType      = 14
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrInvalidInitialAuctionID error for when the initial auction ID hasn't been set
 | 
			
		||||
@ -66,9 +67,9 @@ func ErrInvalidLotDenom(codespace sdk.CodespaceType, lotDenom string, auctionLot
 | 
			
		||||
	return sdk.NewError(codespace, CodeInvalidLotDenom, fmt.Sprintf("lot denom %s doesn't match auction lot denom %s", lotDenom, auctionLotDenom))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrBidTooSmall error for when bid is not greater than auction's last bid
 | 
			
		||||
func ErrBidTooSmall(codespace sdk.CodespaceType, bid sdk.Coin, lastBid sdk.Coin) sdk.Error {
 | 
			
		||||
	return sdk.NewError(codespace, CodeBidTooSmall, fmt.Sprintf("bid %s is not greater than auction's last bid %s", bid.String(), lastBid.String()))
 | 
			
		||||
// ErrBidTooSmall error for when bid is not greater than auction's min bid amount
 | 
			
		||||
func ErrBidTooSmall(codespace sdk.CodespaceType, bid sdk.Coin, minBid sdk.Coin) sdk.Error {
 | 
			
		||||
	return sdk.NewError(codespace, CodeBidTooSmall, fmt.Sprintf("bid %s is not greater than auction's min new bid amount %s", bid.String(), minBid.String()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrBidTooLarge error for when bid is larger than auction's maximum allowed bid
 | 
			
		||||
@ -76,9 +77,14 @@ func ErrBidTooLarge(codespace sdk.CodespaceType, bid sdk.Coin, maxBid sdk.Coin)
 | 
			
		||||
	return sdk.NewError(codespace, CodeBidTooLarge, fmt.Sprintf("bid %s is greater than auction's max bid %s", bid.String(), maxBid.String()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrLotTooLarge error for when lot is not smaller than auction's last lot
 | 
			
		||||
func ErrLotTooLarge(codespace sdk.CodespaceType, lot sdk.Coin, lastLot sdk.Coin) sdk.Error {
 | 
			
		||||
	return sdk.NewError(codespace, CodeLotTooLarge, fmt.Sprintf("lot %s is not less than auction's last lot %s", lot.String(), lastLot.String()))
 | 
			
		||||
// ErrLotToosmall error for when lot is less than zero
 | 
			
		||||
func ErrLotTooSmall(codespace sdk.CodespaceType, lot sdk.Coin, minLot sdk.Coin) sdk.Error {
 | 
			
		||||
	return sdk.NewError(codespace, CodeLotTooSmall, fmt.Sprintf("lot %s is not greater than auction's min new lot amount %s", lot.String(), minLot.String()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrLotTooLarge error for when lot is not smaller than auction's max new lot amount
 | 
			
		||||
func ErrLotTooLarge(codespace sdk.CodespaceType, lot sdk.Coin, maxLot sdk.Coin) sdk.Error {
 | 
			
		||||
	return sdk.NewError(codespace, CodeLotTooLarge, fmt.Sprintf("lot %s is greater than auction's max new lot amount %s", lot.String(), maxLot.String()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrCollateralAuctionIsInReversePhase error for when attempting to place a forward bid on a collateral auction in reverse phase
 | 
			
		||||
 | 
			
		||||
@ -17,11 +17,15 @@ const (
 | 
			
		||||
	DefaultBidDuration time.Duration = 1 * time.Hour
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Parameter keys
 | 
			
		||||
var (
 | 
			
		||||
	// DefaultIncrement is the smallest percent change a new bid must have from the old one
 | 
			
		||||
	DefaultIncrement sdk.Dec = sdk.MustNewDecFromStr("0.05")
 | 
			
		||||
	// ParamStoreKeyParams Param store key for auction params
 | 
			
		||||
	KeyAuctionBidDuration = []byte("BidDuration")
 | 
			
		||||
	KeyAuctionDuration    = []byte("MaxAuctionDuration")
 | 
			
		||||
	KeyBidDuration         = []byte("BidDuration")
 | 
			
		||||
	KeyMaxAuctionDuration  = []byte("MaxAuctionDuration")
 | 
			
		||||
	KeyIncrementSurplus    = []byte("IncrementSurplus")
 | 
			
		||||
	KeyIncrementDebt       = []byte("IncrementDebt")
 | 
			
		||||
	KeyIncrementCollateral = []byte("IncrementCollateral")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ subspace.ParamSet = &Params{}
 | 
			
		||||
@ -30,13 +34,19 @@ var _ subspace.ParamSet = &Params{}
 | 
			
		||||
type Params struct {
 | 
			
		||||
	MaxAuctionDuration  time.Duration `json:"max_auction_duration" yaml:"max_auction_duration"` // max length of auction
 | 
			
		||||
	BidDuration         time.Duration `json:"bid_duration" yaml:"bid_duration"`                 // additional time added to the auction end time after each bid, capped by the expiry.
 | 
			
		||||
	IncrementSurplus    sdk.Dec       `json:"increment_surplus" yaml:"increment_surplus"`       // percentage change (of auc.Bid) required for a new bid on a surplus auction
 | 
			
		||||
	IncrementDebt       sdk.Dec       `json:"increment_debt" yaml:"increment_debt"`             // percentage change (of auc.Lot) required for a new bid on a debt auction
 | 
			
		||||
	IncrementCollateral sdk.Dec       `json:"increment_collateral" yaml:"increment_collateral"` // percentage change (of auc.Bid or auc.Lot) required for a new bid on a collateral auction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewParams returns a new Params object.
 | 
			
		||||
func NewParams(maxAuctionDuration time.Duration, bidDuration time.Duration) Params {
 | 
			
		||||
func NewParams(maxAuctionDuration, bidDuration time.Duration, incrementSurplus, incrementDebt, incrementCollateral sdk.Dec) Params {
 | 
			
		||||
	return Params{
 | 
			
		||||
		MaxAuctionDuration:  maxAuctionDuration,
 | 
			
		||||
		BidDuration:         bidDuration,
 | 
			
		||||
		IncrementSurplus:    incrementSurplus,
 | 
			
		||||
		IncrementDebt:       incrementDebt,
 | 
			
		||||
		IncrementCollateral: incrementCollateral,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -45,6 +55,9 @@ func DefaultParams() Params {
 | 
			
		||||
	return NewParams(
 | 
			
		||||
		DefaultMaxAuctionDuration,
 | 
			
		||||
		DefaultBidDuration,
 | 
			
		||||
		DefaultIncrement,
 | 
			
		||||
		DefaultIncrement,
 | 
			
		||||
		DefaultIncrement,
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -56,8 +69,11 @@ func ParamKeyTable() subspace.KeyTable {
 | 
			
		||||
// ParamSetPairs implements the ParamSet interface and returns all the key/value pairs.
 | 
			
		||||
func (p *Params) ParamSetPairs() subspace.ParamSetPairs {
 | 
			
		||||
	return subspace.ParamSetPairs{
 | 
			
		||||
		{Key: KeyAuctionBidDuration, Value: &p.BidDuration},
 | 
			
		||||
		{Key: KeyAuctionDuration, Value: &p.MaxAuctionDuration},
 | 
			
		||||
		{Key: KeyBidDuration, Value: &p.BidDuration},
 | 
			
		||||
		{Key: KeyMaxAuctionDuration, Value: &p.MaxAuctionDuration},
 | 
			
		||||
		{Key: KeyIncrementSurplus, Value: &p.IncrementSurplus},
 | 
			
		||||
		{Key: KeyIncrementDebt, Value: &p.IncrementDebt},
 | 
			
		||||
		{Key: KeyIncrementCollateral, Value: &p.IncrementCollateral},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -72,7 +88,11 @@ func (p Params) Equal(p2 Params) bool {
 | 
			
		||||
func (p Params) String() string {
 | 
			
		||||
	return fmt.Sprintf(`Auction Params:
 | 
			
		||||
	Max Auction Duration: %s
 | 
			
		||||
	Bid Duration: %s`, p.MaxAuctionDuration, p.BidDuration)
 | 
			
		||||
	Bid Duration: %s
 | 
			
		||||
	Increment Surplus: %s
 | 
			
		||||
	Increment Debt: %s
 | 
			
		||||
	Increment Collateral: %s`,
 | 
			
		||||
		p.MaxAuctionDuration, p.BidDuration, p.IncrementSurplus, p.IncrementDebt, p.IncrementCollateral)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Validate checks that the parameters have valid values.
 | 
			
		||||
@ -86,5 +106,17 @@ func (p Params) Validate() error {
 | 
			
		||||
	if p.BidDuration > p.MaxAuctionDuration {
 | 
			
		||||
		return sdk.ErrInternal("bid duration param cannot be larger than max auction duration")
 | 
			
		||||
	}
 | 
			
		||||
	if p.IncrementSurplus == (sdk.Dec{}) || p.IncrementDebt == (sdk.Dec{}) || p.IncrementCollateral == (sdk.Dec{}) {
 | 
			
		||||
		return sdk.ErrInternal("auction increment values cannot be nil")
 | 
			
		||||
	}
 | 
			
		||||
	if p.IncrementSurplus.IsNegative() {
 | 
			
		||||
		return sdk.ErrInternal("surplus auction increment cannot be less than zero")
 | 
			
		||||
	}
 | 
			
		||||
	if p.IncrementDebt.IsNegative() {
 | 
			
		||||
		return sdk.ErrInternal("debt auction increment cannot be less than zero")
 | 
			
		||||
	}
 | 
			
		||||
	if p.IncrementCollateral.IsNegative() {
 | 
			
		||||
		return sdk.ErrInternal("collateral auction increment cannot be less than zero")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,11 @@
 | 
			
		||||
package types
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestParams_Validate(t *testing.T) {
 | 
			
		||||
@ -11,23 +13,89 @@ func TestParams_Validate(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		name string
 | 
			
		||||
		MaxAuctionDuration time.Duration
 | 
			
		||||
		BidDuration        time.Duration
 | 
			
		||||
		Params
 | 
			
		||||
		expectErr bool
 | 
			
		||||
	}{
 | 
			
		||||
		{"normal", 24 * time.Hour, 1 * time.Hour, false},
 | 
			
		||||
		{"negativeBid", 24 * time.Hour, -1 * time.Hour, true},
 | 
			
		||||
		{"negativeAuction", -24 * time.Hour, 1 * time.Hour, true},
 | 
			
		||||
		{"bid>auction", 1 * time.Hour, 24 * time.Hour, true},
 | 
			
		||||
		{"zeros", 0, 0, false},
 | 
			
		||||
		{
 | 
			
		||||
			"normal",
 | 
			
		||||
			DefaultParams(),
 | 
			
		||||
			false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"negativeBid",
 | 
			
		||||
			Params{
 | 
			
		||||
				MaxAuctionDuration:  24 * time.Hour,
 | 
			
		||||
				BidDuration:         -1 * time.Hour,
 | 
			
		||||
				IncrementSurplus:    d("0.05"),
 | 
			
		||||
				IncrementDebt:       d("0.05"),
 | 
			
		||||
				IncrementCollateral: d("0.05"),
 | 
			
		||||
			},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"negativeAuction",
 | 
			
		||||
			Params{
 | 
			
		||||
				MaxAuctionDuration:  -24 * time.Hour,
 | 
			
		||||
				BidDuration:         1 * time.Hour,
 | 
			
		||||
				IncrementSurplus:    d("0.05"),
 | 
			
		||||
				IncrementDebt:       d("0.05"),
 | 
			
		||||
				IncrementCollateral: d("0.05"),
 | 
			
		||||
			},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"bid>auction",
 | 
			
		||||
			Params{
 | 
			
		||||
				MaxAuctionDuration:  1 * time.Hour,
 | 
			
		||||
				BidDuration:         24 * time.Hour,
 | 
			
		||||
				IncrementSurplus:    d("0.05"),
 | 
			
		||||
				IncrementDebt:       d("0.05"),
 | 
			
		||||
				IncrementCollateral: d("0.05"),
 | 
			
		||||
			},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"negative increment surplus",
 | 
			
		||||
			Params{
 | 
			
		||||
				MaxAuctionDuration:  24 * time.Hour,
 | 
			
		||||
				BidDuration:         1 * time.Hour,
 | 
			
		||||
				IncrementSurplus:    d("-0.05"),
 | 
			
		||||
				IncrementDebt:       d("0.05"),
 | 
			
		||||
				IncrementCollateral: d("0.05"),
 | 
			
		||||
			},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"negative increment debt",
 | 
			
		||||
			Params{
 | 
			
		||||
				MaxAuctionDuration:  24 * time.Hour,
 | 
			
		||||
				BidDuration:         1 * time.Hour,
 | 
			
		||||
				IncrementSurplus:    d("0.05"),
 | 
			
		||||
				IncrementDebt:       d("-0.05"),
 | 
			
		||||
				IncrementCollateral: d("0.05"),
 | 
			
		||||
			},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"negative increment collateral",
 | 
			
		||||
			Params{
 | 
			
		||||
				MaxAuctionDuration:  24 * time.Hour,
 | 
			
		||||
				BidDuration:         1 * time.Hour,
 | 
			
		||||
				IncrementSurplus:    d("0.05"),
 | 
			
		||||
				IncrementDebt:       d("0.05"),
 | 
			
		||||
				IncrementCollateral: d("-0.05"),
 | 
			
		||||
			},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"zero value",
 | 
			
		||||
			Params{},
 | 
			
		||||
			true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tc := range testCases {
 | 
			
		||||
		t.Run(tc.name, func(t *testing.T) {
 | 
			
		||||
			p := Params{
 | 
			
		||||
				MaxAuctionDuration: tc.MaxAuctionDuration,
 | 
			
		||||
				BidDuration:        tc.BidDuration,
 | 
			
		||||
			}
 | 
			
		||||
			err := p.Validate()
 | 
			
		||||
			err := tc.Params.Validate()
 | 
			
		||||
			if tc.expectErr {
 | 
			
		||||
				require.Error(t, err)
 | 
			
		||||
			} else {
 | 
			
		||||
@ -36,3 +104,5 @@ func TestParams_Validate(t *testing.T) {
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func d(amount string) sdk.Dec { return sdk.MustNewDecFromStr(amount) }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user