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
 | 
						// 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
 | 
						// there is nothing left over in the validator fee pool, so as to keep the
 | 
				
			||||||
	// CanWithdrawInvariant invariant.
 | 
						// 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
 | 
						// Note: genutils must occur after staking so that pools are properly
 | 
				
			||||||
	// initialized with tokens from genesis accounts.
 | 
						// initialized with tokens from genesis accounts.
 | 
				
			||||||
 | 
				
			|||||||
@ -4,8 +4,8 @@ import (
 | 
				
			|||||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// EndBlocker runs at the end of every block.
 | 
					// BeginBlocker runs at the start of every block.
 | 
				
			||||||
func EndBlocker(ctx sdk.Context, k Keeper) {
 | 
					func BeginBlocker(ctx sdk.Context, k Keeper) {
 | 
				
			||||||
	err := k.CloseExpiredAuctions(ctx)
 | 
						err := k.CloseExpiredAuctions(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		panic(err)
 | 
							panic(err)
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@ import (
 | 
				
			|||||||
	"github.com/kava-labs/kava/x/cdp"
 | 
						"github.com/kava-labs/kava/x/cdp"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestKeeper_EndBlocker(t *testing.T) {
 | 
					func TestKeeper_BeginBlocker(t *testing.T) {
 | 
				
			||||||
	// Setup
 | 
						// Setup
 | 
				
			||||||
	_, addrs := app.GeneratePrivKeyAddressPairs(2)
 | 
						_, addrs := app.GeneratePrivKeyAddressPairs(2)
 | 
				
			||||||
	buyer := addrs[0]
 | 
						buyer := addrs[0]
 | 
				
			||||||
@ -36,13 +36,14 @@ func TestKeeper_EndBlocker(t *testing.T) {
 | 
				
			|||||||
	ctx := tApp.NewContext(true, abci.Header{})
 | 
						ctx := tApp.NewContext(true, abci.Header{})
 | 
				
			||||||
	keeper := tApp.GetAuctionKeeper()
 | 
						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))
 | 
						auctionID, err := keeper.StartCollateralAuction(ctx, sellerModName, c("token1", 20), c("token2", 50), returnAddrs, returnWeights, c("debt", 40))
 | 
				
			||||||
	require.NoError(t, err)
 | 
						require.NoError(t, err)
 | 
				
			||||||
	require.NoError(t, keeper.PlaceBid(ctx, auctionID, buyer, c("token2", 30)))
 | 
						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)
 | 
						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
 | 
						// Check auction has not been closed yet
 | 
				
			||||||
	_, found := keeper.GetAuction(ctx, auctionID)
 | 
						_, 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
 | 
						// Run the endblocker, simulating a block time equal to auction expiry
 | 
				
			||||||
	expiryTime := ctx.BlockTime().Add(auction.DefaultBidDuration)
 | 
						expiryTime := ctx.BlockTime().Add(auction.DefaultBidDuration)
 | 
				
			||||||
	auction.EndBlocker(ctx.WithBlockTime(expiryTime), keeper)
 | 
						auction.BeginBlocker(ctx.WithBlockTime(expiryTime), keeper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check auction has been closed
 | 
						// Check auction has been closed
 | 
				
			||||||
	_, found = keeper.GetAuction(ctx, auctionID)
 | 
						_, found = keeper.GetAuction(ctx, auctionID)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
// nolint
 | 
					// nolint
 | 
				
			||||||
// autogenerated code using github.com/rigelrozanski/multitool
 | 
					// autogenerated code using github.com/rigelrozanski/multitool
 | 
				
			||||||
// aliases generated for the following subdirectories:
 | 
					// 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
 | 
					package auction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
@ -13,6 +13,7 @@ import (
 | 
				
			|||||||
const (
 | 
					const (
 | 
				
			||||||
	DefaultCodespace                      = types.DefaultCodespace
 | 
						DefaultCodespace                      = types.DefaultCodespace
 | 
				
			||||||
	CodeInvalidInitialAuctionID           = types.CodeInvalidInitialAuctionID
 | 
						CodeInvalidInitialAuctionID           = types.CodeInvalidInitialAuctionID
 | 
				
			||||||
 | 
						CodeInvalidModulePermissions          = types.CodeInvalidModulePermissions
 | 
				
			||||||
	CodeUnrecognizedAuctionType           = types.CodeUnrecognizedAuctionType
 | 
						CodeUnrecognizedAuctionType           = types.CodeUnrecognizedAuctionType
 | 
				
			||||||
	CodeAuctionNotFound                   = types.CodeAuctionNotFound
 | 
						CodeAuctionNotFound                   = types.CodeAuctionNotFound
 | 
				
			||||||
	CodeAuctionHasNotExpired              = types.CodeAuctionHasNotExpired
 | 
						CodeAuctionHasNotExpired              = types.CodeAuctionHasNotExpired
 | 
				
			||||||
@ -21,60 +22,101 @@ const (
 | 
				
			|||||||
	CodeInvalidLotDenom                   = types.CodeInvalidLotDenom
 | 
						CodeInvalidLotDenom                   = types.CodeInvalidLotDenom
 | 
				
			||||||
	CodeBidTooSmall                       = types.CodeBidTooSmall
 | 
						CodeBidTooSmall                       = types.CodeBidTooSmall
 | 
				
			||||||
	CodeBidTooLarge                       = types.CodeBidTooLarge
 | 
						CodeBidTooLarge                       = types.CodeBidTooLarge
 | 
				
			||||||
 | 
						CodeLotTooSmall                       = types.CodeLotTooSmall
 | 
				
			||||||
	CodeLotTooLarge                       = types.CodeLotTooLarge
 | 
						CodeLotTooLarge                       = types.CodeLotTooLarge
 | 
				
			||||||
	CodeCollateralAuctionIsInReversePhase = types.CodeCollateralAuctionIsInReversePhase
 | 
						CodeCollateralAuctionIsInReversePhase = types.CodeCollateralAuctionIsInReversePhase
 | 
				
			||||||
	CodeCollateralAuctionIsInForwardPhase = types.CodeCollateralAuctionIsInForwardPhase
 | 
						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
 | 
						ModuleName                            = types.ModuleName
 | 
				
			||||||
	StoreKey                              = types.StoreKey
 | 
						StoreKey                              = types.StoreKey
 | 
				
			||||||
	RouterKey                             = types.RouterKey
 | 
						RouterKey                             = types.RouterKey
 | 
				
			||||||
	DefaultParamspace                     = types.DefaultParamspace
 | 
						DefaultParamspace                     = types.DefaultParamspace
 | 
				
			||||||
 | 
						QuerierRoute                          = types.QuerierRoute
 | 
				
			||||||
	DefaultMaxAuctionDuration             = types.DefaultMaxAuctionDuration
 | 
						DefaultMaxAuctionDuration             = types.DefaultMaxAuctionDuration
 | 
				
			||||||
	DefaultBidDuration                    = types.DefaultBidDuration
 | 
						DefaultBidDuration                    = types.DefaultBidDuration
 | 
				
			||||||
	QueryGetAuction                       = types.QueryGetAuction
 | 
						QueryGetAuction                       = types.QueryGetAuction
 | 
				
			||||||
	DefaultNextAuctionID                  = types.DefaultNextAuctionID
 | 
						QueryGetAuctions                      = types.QueryGetAuctions
 | 
				
			||||||
 | 
						QueryGetParams                        = types.QueryGetParams
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	// functions aliases
 | 
						// functions aliases
 | 
				
			||||||
	NewSurplusAuction    = types.NewSurplusAuction
 | 
						NewKeeper                            = keeper.NewKeeper
 | 
				
			||||||
	NewDebtAuction       = types.NewDebtAuction
 | 
						NewQuerier                           = keeper.NewQuerier
 | 
				
			||||||
	NewCollateralAuction = types.NewCollateralAuction
 | 
						NewSurplusAuction                    = types.NewSurplusAuction
 | 
				
			||||||
	NewWeightedAddresses = types.NewWeightedAddresses
 | 
						NewDebtAuction                       = types.NewDebtAuction
 | 
				
			||||||
	RegisterCodec        = types.RegisterCodec
 | 
						NewCollateralAuction                 = types.NewCollateralAuction
 | 
				
			||||||
	NewGenesisState      = types.NewGenesisState
 | 
						NewWeightedAddresses                 = types.NewWeightedAddresses
 | 
				
			||||||
	DefaultGenesisState  = types.DefaultGenesisState
 | 
						RegisterCodec                        = types.RegisterCodec
 | 
				
			||||||
	GetAuctionKey        = types.GetAuctionKey
 | 
						ErrInvalidInitialAuctionID           = types.ErrInvalidInitialAuctionID
 | 
				
			||||||
	GetAuctionByTimeKey  = types.GetAuctionByTimeKey
 | 
						ErrInvalidModulePermissions          = types.ErrInvalidModulePermissions
 | 
				
			||||||
	Uint64FromBytes      = types.Uint64FromBytes
 | 
						ErrUnrecognizedAuctionType           = types.ErrUnrecognizedAuctionType
 | 
				
			||||||
	Uint64ToBytes        = types.Uint64ToBytes
 | 
						ErrAuctionNotFound                   = types.ErrAuctionNotFound
 | 
				
			||||||
	NewMsgPlaceBid       = types.NewMsgPlaceBid
 | 
						ErrAuctionHasNotExpired              = types.ErrAuctionHasNotExpired
 | 
				
			||||||
	NewParams            = types.NewParams
 | 
						ErrAuctionHasExpired                 = types.ErrAuctionHasExpired
 | 
				
			||||||
	DefaultParams        = types.DefaultParams
 | 
						ErrInvalidBidDenom                   = types.ErrInvalidBidDenom
 | 
				
			||||||
	ParamKeyTable        = types.ParamKeyTable
 | 
						ErrInvalidLotDenom                   = types.ErrInvalidLotDenom
 | 
				
			||||||
	NewKeeper            = keeper.NewKeeper
 | 
						ErrBidTooSmall                       = types.ErrBidTooSmall
 | 
				
			||||||
	NewQuerier           = keeper.NewQuerier
 | 
						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
 | 
				
			||||||
 | 
						Uint64ToBytes                        = types.Uint64ToBytes
 | 
				
			||||||
 | 
						Uint64FromBytes                      = types.Uint64FromBytes
 | 
				
			||||||
 | 
						NewMsgPlaceBid                       = types.NewMsgPlaceBid
 | 
				
			||||||
 | 
						NewParams                            = types.NewParams
 | 
				
			||||||
 | 
						DefaultParams                        = types.DefaultParams
 | 
				
			||||||
 | 
						ParamKeyTable                        = types.ParamKeyTable
 | 
				
			||||||
 | 
						NewQueryAllAuctionParams             = types.NewQueryAllAuctionParams
 | 
				
			||||||
 | 
						NewAuctionWithPhase                  = types.NewAuctionWithPhase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// variable aliases
 | 
						// variable aliases
 | 
				
			||||||
 | 
						DistantFuture          = types.DistantFuture
 | 
				
			||||||
	ModuleCdc              = types.ModuleCdc
 | 
						ModuleCdc              = types.ModuleCdc
 | 
				
			||||||
	AuctionKeyPrefix       = types.AuctionKeyPrefix
 | 
						AuctionKeyPrefix       = types.AuctionKeyPrefix
 | 
				
			||||||
	AuctionByTimeKeyPrefix = types.AuctionByTimeKeyPrefix
 | 
						AuctionByTimeKeyPrefix = types.AuctionByTimeKeyPrefix
 | 
				
			||||||
	NextAuctionIDKey       = types.NextAuctionIDKey
 | 
						NextAuctionIDKey       = types.NextAuctionIDKey
 | 
				
			||||||
	KeyAuctionBidDuration  = types.KeyAuctionBidDuration
 | 
						DefaultIncrement       = types.DefaultIncrement
 | 
				
			||||||
	KeyAuctionDuration     = types.KeyAuctionDuration
 | 
						KeyBidDuration         = types.KeyBidDuration
 | 
				
			||||||
 | 
						KeyMaxAuctionDuration  = types.KeyMaxAuctionDuration
 | 
				
			||||||
 | 
						KeyIncrementSurplus    = types.KeyIncrementSurplus
 | 
				
			||||||
 | 
						KeyIncrementDebt       = types.KeyIncrementDebt
 | 
				
			||||||
 | 
						KeyIncrementCollateral = types.KeyIncrementCollateral
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type (
 | 
					type (
 | 
				
			||||||
	Auction           = types.Auction
 | 
						Keeper                = keeper.Keeper
 | 
				
			||||||
	BaseAuction       = types.BaseAuction
 | 
						Auction               = types.Auction
 | 
				
			||||||
	SurplusAuction    = types.SurplusAuction
 | 
						Auctions              = types.Auctions
 | 
				
			||||||
	DebtAuction       = types.DebtAuction
 | 
						BaseAuction           = types.BaseAuction
 | 
				
			||||||
	CollateralAuction = types.CollateralAuction
 | 
						SurplusAuction        = types.SurplusAuction
 | 
				
			||||||
	WeightedAddresses = types.WeightedAddresses
 | 
						DebtAuction           = types.DebtAuction
 | 
				
			||||||
	SupplyKeeper      = types.SupplyKeeper
 | 
						CollateralAuction     = types.CollateralAuction
 | 
				
			||||||
	GenesisAuctions   = types.GenesisAuctions
 | 
						WeightedAddresses     = types.WeightedAddresses
 | 
				
			||||||
	GenesisAuction    = types.GenesisAuction
 | 
						SupplyKeeper          = types.SupplyKeeper
 | 
				
			||||||
	GenesisState      = types.GenesisState
 | 
						GenesisAuction        = types.GenesisAuction
 | 
				
			||||||
	MsgPlaceBid       = types.MsgPlaceBid
 | 
						GenesisAuctions       = types.GenesisAuctions
 | 
				
			||||||
	Params            = types.Params
 | 
						GenesisState          = types.GenesisState
 | 
				
			||||||
	Keeper            = keeper.Keeper
 | 
						MsgPlaceBid           = types.MsgPlaceBid
 | 
				
			||||||
 | 
						Params                = types.Params
 | 
				
			||||||
 | 
						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 {
 | 
						if bid.Denom != a.Bid.Denom {
 | 
				
			||||||
		return a, types.ErrInvalidBidDenom(k.codespace, bid.Denom, a.Bid.Denom)
 | 
							return a, types.ErrInvalidBidDenom(k.codespace, bid.Denom, a.Bid.Denom)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !a.Bid.IsLT(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
 | 
				
			||||||
		return a, types.ErrBidTooSmall(k.codespace, bid, a.Bid)
 | 
							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
 | 
						// New bidder pays back old bidder
 | 
				
			||||||
@ -225,8 +231,15 @@ func (k Keeper) PlaceForwardBidCollateral(ctx sdk.Context, a types.CollateralAuc
 | 
				
			|||||||
	if a.IsReversePhase() {
 | 
						if a.IsReversePhase() {
 | 
				
			||||||
		return a, types.ErrCollateralAuctionIsInReversePhase(k.codespace, a.ID)
 | 
							return a, types.ErrCollateralAuctionIsInReversePhase(k.codespace, a.ID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !a.Bid.IsLT(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
 | 
				
			||||||
		return a, types.ErrBidTooSmall(k.codespace, bid, a.Bid)
 | 
							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) {
 | 
						if a.MaxBid.IsLT(bid) {
 | 
				
			||||||
		return a, types.ErrBidTooLarge(k.codespace, bid, a.MaxBid)
 | 
							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() {
 | 
						if !a.IsReversePhase() {
 | 
				
			||||||
		return a, types.ErrCollateralAuctionIsInForwardPhase(k.codespace, a.ID)
 | 
							return a, types.ErrCollateralAuctionIsInForwardPhase(k.codespace, a.ID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !lot.IsLT(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
 | 
				
			||||||
		return a, types.ErrLotTooLarge(k.codespace, lot, a.Lot)
 | 
							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
 | 
						// 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 {
 | 
						if lot.Denom != a.Lot.Denom {
 | 
				
			||||||
		return a, types.ErrInvalidLotDenom(k.codespace, lot.Denom, a.Lot.Denom)
 | 
							return a, types.ErrInvalidLotDenom(k.codespace, lot.Denom, a.Lot.Denom)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !lot.IsLT(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
 | 
				
			||||||
		return a, types.ErrLotTooLarge(k.codespace, lot, a.Lot)
 | 
							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
 | 
						// New bidder pays back old bidder
 | 
				
			||||||
 | 
				
			|||||||
@ -19,11 +19,10 @@ import (
 | 
				
			|||||||
type AuctionType int
 | 
					type AuctionType int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	Invalid          AuctionType = 0
 | 
						Invalid    AuctionType = 0
 | 
				
			||||||
	Surplus          AuctionType = 1
 | 
						Surplus    AuctionType = 1
 | 
				
			||||||
	Debt             AuctionType = 2
 | 
						Debt       AuctionType = 2
 | 
				
			||||||
	CollateralPhase1 AuctionType = 3
 | 
						Collateral AuctionType = 3
 | 
				
			||||||
	CollateralPhase2 AuctionType = 4
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestAuctionBidding(t *testing.T) {
 | 
					func TestAuctionBidding(t *testing.T) {
 | 
				
			||||||
@ -47,14 +46,14 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	type bidArgs struct {
 | 
						type bidArgs struct {
 | 
				
			||||||
		bidder       sdk.AccAddress
 | 
							bidder sdk.AccAddress
 | 
				
			||||||
		amount       sdk.Coin
 | 
							amount sdk.Coin
 | 
				
			||||||
		secondBidder sdk.AccAddress
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		name            string
 | 
							name            string
 | 
				
			||||||
		auctionArgs     auctionArgs
 | 
							auctionArgs     auctionArgs
 | 
				
			||||||
 | 
							setupBids       []bidArgs
 | 
				
			||||||
		bidArgs         bidArgs
 | 
							bidArgs         bidArgs
 | 
				
			||||||
		expectedError   sdk.CodeType
 | 
							expectedError   sdk.CodeType
 | 
				
			||||||
		expectedEndTime time.Time
 | 
							expectedEndTime time.Time
 | 
				
			||||||
@ -65,17 +64,30 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
		{
 | 
							{
 | 
				
			||||||
			"basic: auction doesn't exist",
 | 
								"basic: auction doesn't exist",
 | 
				
			||||||
			auctionArgs{Surplus, "", c("token1", 1), c("token2", 1), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
								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,
 | 
								types.CodeAuctionNotFound,
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			buyer,
 | 
								buyer,
 | 
				
			||||||
			c("token2", 10),
 | 
								c("token2", 10),
 | 
				
			||||||
			false,
 | 
								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",
 | 
								"surplus: normal",
 | 
				
			||||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
								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),
 | 
								sdk.CodeType(0),
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			buyer,
 | 
								buyer,
 | 
				
			||||||
@ -85,7 +97,8 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
		{
 | 
							{
 | 
				
			||||||
			"surplus: second bidder",
 | 
								"surplus: second bidder",
 | 
				
			||||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
								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),
 | 
								sdk.CodeType(0),
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			secondBuyer,
 | 
								secondBuyer,
 | 
				
			||||||
@ -95,27 +108,52 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
		{
 | 
							{
 | 
				
			||||||
			"surplus: invalid bid denom",
 | 
								"surplus: invalid bid denom",
 | 
				
			||||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
								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.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),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			buyer,
 | 
								buyer,
 | 
				
			||||||
			c("token2", 10),
 | 
								c("token2", 100),
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"surplus: invalid bid (equal)",
 | 
								"surplus: invalid bid (equal)",
 | 
				
			||||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
								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,
 | 
								types.CodeBidTooSmall,
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			buyer,
 | 
								buyer,
 | 
				
			||||||
			c("token2", 10),
 | 
								c("token2", 100),
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"debt: normal",
 | 
								"debt: normal",
 | 
				
			||||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 20), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
 | 
								auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
 | 
				
			||||||
			bidArgs{buyer, c("token1", 10), nil},
 | 
								nil,
 | 
				
			||||||
 | 
								bidArgs{buyer, c("token1", 10)},
 | 
				
			||||||
			sdk.CodeType(0),
 | 
								sdk.CodeType(0),
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			buyer,
 | 
								buyer,
 | 
				
			||||||
@ -124,8 +162,9 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"debt: second bidder",
 | 
								"debt: second bidder",
 | 
				
			||||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 20), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
 | 
								auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
 | 
				
			||||||
			bidArgs{buyer, c("token1", 10), secondBuyer},
 | 
								[]bidArgs{{buyer, c("token1", 10)}},
 | 
				
			||||||
 | 
								bidArgs{secondBuyer, c("token1", 9)},
 | 
				
			||||||
			sdk.CodeType(0),
 | 
								sdk.CodeType(0),
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			secondBuyer,
 | 
								secondBuyer,
 | 
				
			||||||
@ -134,28 +173,53 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"debt: invalid lot denom",
 | 
								"debt: invalid lot denom",
 | 
				
			||||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 20), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
 | 
								auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
 | 
				
			||||||
			bidArgs{buyer, c("badtoken", 10), nil},
 | 
								nil,
 | 
				
			||||||
 | 
								bidArgs{buyer, c("badtoken", 10)},
 | 
				
			||||||
			types.CodeInvalidLotDenom,
 | 
								types.CodeInvalidLotDenom,
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								types.DistantFuture,
 | 
				
			||||||
			buyer,
 | 
								supply.NewModuleAddress(modName),
 | 
				
			||||||
			c("token1", 20),
 | 
								c("token2", 100),
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"debt: invalid lot size (larger)",
 | 
								"debt: invalid lot size (larger)",
 | 
				
			||||||
			auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 20), []sdk.AccAddress{}, []sdk.Int{}},
 | 
								auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}},
 | 
				
			||||||
			bidArgs{buyer, c("token1", 21), nil},
 | 
								nil,
 | 
				
			||||||
 | 
								bidArgs{buyer, c("token1", 21)},
 | 
				
			||||||
			types.CodeLotTooLarge,
 | 
								types.CodeLotTooLarge,
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								types.DistantFuture,
 | 
				
			||||||
			buyer,
 | 
								supply.NewModuleAddress(modName),
 | 
				
			||||||
			c("token1", 20),
 | 
								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,
 | 
								false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"collateral [forward]: normal",
 | 
								"collateral [forward]: normal",
 | 
				
			||||||
			auctionArgs{CollateralPhase1, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
								auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
				
			||||||
			bidArgs{buyer, c("token2", 10), nil},
 | 
								nil,
 | 
				
			||||||
 | 
								bidArgs{buyer, c("token2", 10)},
 | 
				
			||||||
			sdk.CodeType(0),
 | 
								sdk.CodeType(0),
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			buyer,
 | 
								buyer,
 | 
				
			||||||
@ -164,8 +228,9 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"collateral [forward]: second bidder",
 | 
								"collateral [forward]: second bidder",
 | 
				
			||||||
			auctionArgs{CollateralPhase1, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
								auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
				
			||||||
			bidArgs{buyer, c("token2", 10), secondBuyer},
 | 
								[]bidArgs{{buyer, c("token2", 10)}},
 | 
				
			||||||
 | 
								bidArgs{secondBuyer, c("token2", 11)},
 | 
				
			||||||
			sdk.CodeType(0),
 | 
								sdk.CodeType(0),
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			secondBuyer,
 | 
								secondBuyer,
 | 
				
			||||||
@ -174,18 +239,20 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"collateral [forward]: invalid bid denom",
 | 
								"collateral [forward]: invalid bid denom",
 | 
				
			||||||
			auctionArgs{CollateralPhase1, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
								auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
				
			||||||
			bidArgs{buyer, c("badtoken", 10), nil},
 | 
								nil,
 | 
				
			||||||
 | 
								bidArgs{buyer, c("badtoken", 10)},
 | 
				
			||||||
			types.CodeInvalidBidDenom,
 | 
								types.CodeInvalidBidDenom,
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								types.DistantFuture,
 | 
				
			||||||
			buyer,
 | 
								nil,
 | 
				
			||||||
			c("token2", 10),
 | 
								c("token2", 0),
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"collateral [forward]: invalid bid size (smaller)",
 | 
								"collateral [forward]: invalid bid size (smaller)",
 | 
				
			||||||
			auctionArgs{CollateralPhase1, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
								auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
				
			||||||
			bidArgs{buyer, c("token2", 0), nil},                                                                                          // lot, bid
 | 
								[]bidArgs{{buyer, c("token2", 10)}},
 | 
				
			||||||
 | 
								bidArgs{buyer, c("token2", 9)},
 | 
				
			||||||
			types.CodeBidTooSmall,
 | 
								types.CodeBidTooSmall,
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			buyer,
 | 
								buyer,
 | 
				
			||||||
@ -193,19 +260,54 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
			false,
 | 
								false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"collateral [forward]: invalid bid size (greater than max)",
 | 
								"collateral [forward]: invalid bid size (equal)",
 | 
				
			||||||
			auctionArgs{CollateralPhase1, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
								auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
				
			||||||
			bidArgs{buyer, c("token2", 101), nil},                                                                                        // lot, bid
 | 
								nil,
 | 
				
			||||||
			types.CodeBidTooLarge,
 | 
								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),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			buyer,
 | 
								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,
 | 
								false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"collateral [reverse]: normal",
 | 
								"collateral [reverse]: normal",
 | 
				
			||||||
			auctionArgs{CollateralPhase2, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
								auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
				
			||||||
			bidArgs{buyer, c("token1", 15), nil},
 | 
								[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
 | 
				
			||||||
 | 
								bidArgs{buyer, c("token1", 15)},
 | 
				
			||||||
			sdk.CodeType(0),
 | 
								sdk.CodeType(0),
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			buyer,
 | 
								buyer,
 | 
				
			||||||
@ -214,8 +316,9 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"collateral [reverse]: second bidder",
 | 
								"collateral [reverse]: second bidder",
 | 
				
			||||||
			auctionArgs{CollateralPhase2, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
								auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
				
			||||||
			bidArgs{buyer, c("token1", 15), secondBuyer},
 | 
								[]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),
 | 
								sdk.CodeType(0),
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			secondBuyer,
 | 
								secondBuyer,
 | 
				
			||||||
@ -224,28 +327,20 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"collateral [reverse]: invalid lot denom",
 | 
								"collateral [reverse]: invalid lot denom",
 | 
				
			||||||
			auctionArgs{CollateralPhase2, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
								auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
				
			||||||
			bidArgs{buyer, c("badtoken", 15), nil},
 | 
								[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
 | 
				
			||||||
 | 
								bidArgs{buyer, c("badtoken", 15)},
 | 
				
			||||||
			types.CodeInvalidLotDenom,
 | 
								types.CodeInvalidLotDenom,
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			buyer,
 | 
								buyer,
 | 
				
			||||||
			c("token2", 50),
 | 
								c("token2", 50),
 | 
				
			||||||
			false,
 | 
								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)",
 | 
								"collateral [reverse]: invalid lot size (greater)",
 | 
				
			||||||
			auctionArgs{CollateralPhase2, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
								auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
				
			||||||
			bidArgs{buyer, c("token1", 21), nil},
 | 
								[]bidArgs{{buyer, c("token2", 50)}},                                                                                   // put auction into reverse phase
 | 
				
			||||||
 | 
								bidArgs{buyer, c("token1", 21)},
 | 
				
			||||||
			types.CodeLotTooLarge,
 | 
								types.CodeLotTooLarge,
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			buyer,
 | 
								buyer,
 | 
				
			||||||
@ -253,13 +348,25 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
			false,
 | 
								false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"basic: closed auction",
 | 
								"collateral [reverse]: invalid lot size (equal)",
 | 
				
			||||||
			auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
 | 
								auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
 | 
				
			||||||
			bidArgs{buyer, c("token2", 10), nil},
 | 
								[]bidArgs{{buyer, c("token2", 50)}},                                                                                   // put auction into reverse phase
 | 
				
			||||||
			types.CodeAuctionHasExpired,
 | 
								bidArgs{buyer, c("token1", 20)},
 | 
				
			||||||
 | 
								types.CodeLotTooLarge,
 | 
				
			||||||
			someTime.Add(types.DefaultBidDuration),
 | 
								someTime.Add(types.DefaultBidDuration),
 | 
				
			||||||
			buyer,
 | 
								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,
 | 
								false,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -283,6 +390,7 @@ func TestAuctionBidding(t *testing.T) {
 | 
				
			|||||||
			)
 | 
								)
 | 
				
			||||||
			ctx := tApp.NewContext(false, abci.Header{})
 | 
								ctx := tApp.NewContext(false, abci.Header{})
 | 
				
			||||||
			keeper := tApp.GetAuctionKeeper()
 | 
								keeper := tApp.GetAuctionKeeper()
 | 
				
			||||||
 | 
								bank := tApp.GetBankKeeper()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Start Auction
 | 
								// Start Auction
 | 
				
			||||||
			var id uint64
 | 
								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)
 | 
									id, _ = keeper.StartSurplusAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.lot, tc.auctionArgs.bid.Denom)
 | 
				
			||||||
			case Debt:
 | 
								case Debt:
 | 
				
			||||||
				id, _ = keeper.StartDebtAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.bid, tc.auctionArgs.lot, tc.auctionArgs.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
 | 
									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:
 | 
								default:
 | 
				
			||||||
				t.Fail()
 | 
									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)
 | 
								// Close the auction early to test late bidding (if applicable)
 | 
				
			||||||
			if strings.Contains(tc.name, "closed") {
 | 
								if strings.Contains(tc.name, "closed") {
 | 
				
			||||||
				ctx = ctx.WithBlockTime(types.DistantFuture.Add(1))
 | 
									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
 | 
								// Place bid on auction
 | 
				
			||||||
			err = keeper.PlaceBid(ctx, id, tc.bidArgs.bidder, tc.bidArgs.amount)
 | 
								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
 | 
								// Check success/failure
 | 
				
			||||||
			if tc.expectpass {
 | 
								if tc.expectpass {
 | 
				
			||||||
				require.Nil(t, err)
 | 
									require.Nil(t, err)
 | 
				
			||||||
				// Get auction from store
 | 
									// Check auction was found
 | 
				
			||||||
				auction, found := keeper.GetAuction(ctx, id)
 | 
									newAuction, found := keeper.GetAuction(ctx, id)
 | 
				
			||||||
				require.True(t, found)
 | 
									require.True(t, found)
 | 
				
			||||||
				// Check auction values
 | 
									// Check auction values
 | 
				
			||||||
				require.Equal(t, modName, auction.GetInitiator())
 | 
									require.Equal(t, modName, newAuction.GetInitiator())
 | 
				
			||||||
				require.Equal(t, tc.expectedBidder, auction.GetBidder())
 | 
									require.Equal(t, tc.expectedBidder, newAuction.GetBidder())
 | 
				
			||||||
				require.Equal(t, tc.expectedBid, auction.GetBid())
 | 
									require.Equal(t, tc.expectedBid, newAuction.GetBid())
 | 
				
			||||||
				require.Equal(t, tc.expectedEndTime, auction.GetEndTime())
 | 
									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 {
 | 
								} else {
 | 
				
			||||||
				// Check expected error code type
 | 
									// 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)
 | 
									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
 | 
					// 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
 | 
					// EndBlock module end-block
 | 
				
			||||||
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
 | 
					func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
 | 
				
			||||||
	EndBlocker(ctx, am.keeper)
 | 
					 | 
				
			||||||
	return []abci.ValidatorUpdate{}
 | 
						return []abci.ValidatorUpdate{}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,9 @@
 | 
				
			|||||||
type Params struct {
 | 
					type Params struct {
 | 
				
			||||||
	MaxAuctionDuration time.Duration `json:"max_auction_duration" yaml:"max_auction_duration"` // max length of auction
 | 
						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.
 | 
						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     | module        | auction            |
 | 
				
			||||||
| message     | sender        | {sender address}   |
 | 
					| message     | sender        | {sender address}   |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## EndBlock
 | 
					## BeginBlock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Type          | Attribute Key | Attribute Value |
 | 
					| Type          | Attribute Key | Attribute Value |
 | 
				
			||||||
|---------------|---------------|-----------------|
 | 
					|---------------|---------------|-----------------|
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
The auction module contains the following parameters:
 | 
					The auction module contains the following parameters:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Key                | Type                   | Example    |
 | 
					| Key                 | Type                   | Example                | Description                                                                           |
 | 
				
			||||||
| ------------------ | ---------------------- | -----------|
 | 
					|---------------------|------------------------|------------------------|---------------------------------------------------------------------------------------|
 | 
				
			||||||
| MaxAuctionDuration | string (time.Duration) | "48h0m0s"  |
 | 
					| MaxAuctionDuration  | string (time.Duration) | "48h0m0s"              |                                                                                       |
 | 
				
			||||||
| BidDuration        | string (time.Duration) | "3h0m0s"   |
 | 
					| 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
 | 
					```go
 | 
				
			||||||
var expiredAuctions []uint64
 | 
					var expiredAuctions []uint64
 | 
				
			||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
3. **[Messages](03_messages.md)**
 | 
					3. **[Messages](03_messages.md)**
 | 
				
			||||||
4. **[Events](04_events.md)**
 | 
					4. **[Events](04_events.md)**
 | 
				
			||||||
5. **[Params](05_params.md)**
 | 
					5. **[Params](05_params.md)**
 | 
				
			||||||
6. **[EndBlock](06_end_block.md)**
 | 
					6. **[BeginBlock](06_begin_block.md)**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Abstract
 | 
					## Abstract
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -61,7 +61,7 @@ func (a BaseAuction) GetBid() sdk.Coin { return a.Bid }
 | 
				
			|||||||
// GetEndTime is a getter for auction end time.
 | 
					// GetEndTime is a getter for auction end time.
 | 
				
			||||||
func (a BaseAuction) GetEndTime() time.Time { return a.EndTime }
 | 
					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" }
 | 
					func (a BaseAuction) GetType() string { return "base" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Validate verifies that the auction end time is before max end time
 | 
					// Validate verifies that the auction end time is before max end time
 | 
				
			||||||
 | 
				
			|||||||
@ -21,9 +21,10 @@ const (
 | 
				
			|||||||
	CodeInvalidLotDenom                   sdk.CodeType      = 8
 | 
						CodeInvalidLotDenom                   sdk.CodeType      = 8
 | 
				
			||||||
	CodeBidTooSmall                       sdk.CodeType      = 9
 | 
						CodeBidTooSmall                       sdk.CodeType      = 9
 | 
				
			||||||
	CodeBidTooLarge                       sdk.CodeType      = 10
 | 
						CodeBidTooLarge                       sdk.CodeType      = 10
 | 
				
			||||||
	CodeLotTooLarge                       sdk.CodeType      = 11
 | 
						CodeLotTooSmall                       sdk.CodeType      = 11
 | 
				
			||||||
	CodeCollateralAuctionIsInReversePhase sdk.CodeType      = 12
 | 
						CodeLotTooLarge                       sdk.CodeType      = 12
 | 
				
			||||||
	CodeCollateralAuctionIsInForwardPhase sdk.CodeType      = 13
 | 
						CodeCollateralAuctionIsInReversePhase sdk.CodeType      = 13
 | 
				
			||||||
 | 
						CodeCollateralAuctionIsInForwardPhase sdk.CodeType      = 14
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ErrInvalidInitialAuctionID error for when the initial auction ID hasn't been set
 | 
					// 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))
 | 
						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
 | 
					// ErrBidTooSmall error for when bid is not greater than auction's min bid amount
 | 
				
			||||||
func ErrBidTooSmall(codespace sdk.CodespaceType, bid sdk.Coin, lastBid sdk.Coin) sdk.Error {
 | 
					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 last bid %s", bid.String(), lastBid.String()))
 | 
						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
 | 
					// 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()))
 | 
						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
 | 
					// ErrLotToosmall error for when lot is less than zero
 | 
				
			||||||
func ErrLotTooLarge(codespace sdk.CodespaceType, lot sdk.Coin, lastLot sdk.Coin) sdk.Error {
 | 
					func ErrLotTooSmall(codespace sdk.CodespaceType, lot sdk.Coin, minLot 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()))
 | 
						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
 | 
					// ErrCollateralAuctionIsInReversePhase error for when attempting to place a forward bid on a collateral auction in reverse phase
 | 
				
			||||||
 | 
				
			|||||||
@ -17,26 +17,36 @@ const (
 | 
				
			|||||||
	DefaultBidDuration time.Duration = 1 * time.Hour
 | 
						DefaultBidDuration time.Duration = 1 * time.Hour
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Parameter keys
 | 
					 | 
				
			||||||
var (
 | 
					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
 | 
						// ParamStoreKeyParams Param store key for auction params
 | 
				
			||||||
	KeyAuctionBidDuration = []byte("BidDuration")
 | 
						KeyBidDuration         = []byte("BidDuration")
 | 
				
			||||||
	KeyAuctionDuration    = []byte("MaxAuctionDuration")
 | 
						KeyMaxAuctionDuration  = []byte("MaxAuctionDuration")
 | 
				
			||||||
 | 
						KeyIncrementSurplus    = []byte("IncrementSurplus")
 | 
				
			||||||
 | 
						KeyIncrementDebt       = []byte("IncrementDebt")
 | 
				
			||||||
 | 
						KeyIncrementCollateral = []byte("IncrementCollateral")
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var _ subspace.ParamSet = &Params{}
 | 
					var _ subspace.ParamSet = &Params{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Params is the governance parameters for the auction module.
 | 
					// Params is the governance parameters for the auction module.
 | 
				
			||||||
type Params struct {
 | 
					type Params struct {
 | 
				
			||||||
	MaxAuctionDuration time.Duration `json:"max_auction_duration" yaml:"max_auction_duration"` // max length of auction
 | 
						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.
 | 
						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.
 | 
					// 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{
 | 
						return Params{
 | 
				
			||||||
		MaxAuctionDuration: maxAuctionDuration,
 | 
							MaxAuctionDuration:  maxAuctionDuration,
 | 
				
			||||||
		BidDuration:        bidDuration,
 | 
							BidDuration:         bidDuration,
 | 
				
			||||||
 | 
							IncrementSurplus:    incrementSurplus,
 | 
				
			||||||
 | 
							IncrementDebt:       incrementDebt,
 | 
				
			||||||
 | 
							IncrementCollateral: incrementCollateral,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -45,6 +55,9 @@ func DefaultParams() Params {
 | 
				
			|||||||
	return NewParams(
 | 
						return NewParams(
 | 
				
			||||||
		DefaultMaxAuctionDuration,
 | 
							DefaultMaxAuctionDuration,
 | 
				
			||||||
		DefaultBidDuration,
 | 
							DefaultBidDuration,
 | 
				
			||||||
 | 
							DefaultIncrement,
 | 
				
			||||||
 | 
							DefaultIncrement,
 | 
				
			||||||
 | 
							DefaultIncrement,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -56,8 +69,11 @@ func ParamKeyTable() subspace.KeyTable {
 | 
				
			|||||||
// ParamSetPairs implements the ParamSet interface and returns all the key/value pairs.
 | 
					// ParamSetPairs implements the ParamSet interface and returns all the key/value pairs.
 | 
				
			||||||
func (p *Params) ParamSetPairs() subspace.ParamSetPairs {
 | 
					func (p *Params) ParamSetPairs() subspace.ParamSetPairs {
 | 
				
			||||||
	return subspace.ParamSetPairs{
 | 
						return subspace.ParamSetPairs{
 | 
				
			||||||
		{Key: KeyAuctionBidDuration, Value: &p.BidDuration},
 | 
							{Key: KeyBidDuration, Value: &p.BidDuration},
 | 
				
			||||||
		{Key: KeyAuctionDuration, Value: &p.MaxAuctionDuration},
 | 
							{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 {
 | 
					func (p Params) String() string {
 | 
				
			||||||
	return fmt.Sprintf(`Auction Params:
 | 
						return fmt.Sprintf(`Auction Params:
 | 
				
			||||||
	Max Auction Duration: %s
 | 
						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.
 | 
					// Validate checks that the parameters have valid values.
 | 
				
			||||||
@ -86,5 +106,17 @@ func (p Params) Validate() error {
 | 
				
			|||||||
	if p.BidDuration > p.MaxAuctionDuration {
 | 
						if p.BidDuration > p.MaxAuctionDuration {
 | 
				
			||||||
		return sdk.ErrInternal("bid duration param cannot be larger than max auction duration")
 | 
							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
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,33 +1,101 @@
 | 
				
			|||||||
package types
 | 
					package types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
					 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestParams_Validate(t *testing.T) {
 | 
					func TestParams_Validate(t *testing.T) {
 | 
				
			||||||
	type fields struct {
 | 
						type fields struct {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	testCases := []struct {
 | 
						testCases := []struct {
 | 
				
			||||||
		name               string
 | 
							name string
 | 
				
			||||||
		MaxAuctionDuration time.Duration
 | 
							Params
 | 
				
			||||||
		BidDuration        time.Duration
 | 
							expectErr bool
 | 
				
			||||||
		expectErr          bool
 | 
					 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{"normal", 24 * time.Hour, 1 * time.Hour, false},
 | 
							{
 | 
				
			||||||
		{"negativeBid", 24 * time.Hour, -1 * time.Hour, true},
 | 
								"normal",
 | 
				
			||||||
		{"negativeAuction", -24 * time.Hour, 1 * time.Hour, true},
 | 
								DefaultParams(),
 | 
				
			||||||
		{"bid>auction", 1 * time.Hour, 24 * time.Hour, true},
 | 
								false,
 | 
				
			||||||
		{"zeros", 0, 0, 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 {
 | 
						for _, tc := range testCases {
 | 
				
			||||||
		t.Run(tc.name, func(t *testing.T) {
 | 
							t.Run(tc.name, func(t *testing.T) {
 | 
				
			||||||
			p := Params{
 | 
								err := tc.Params.Validate()
 | 
				
			||||||
				MaxAuctionDuration: tc.MaxAuctionDuration,
 | 
					 | 
				
			||||||
				BidDuration:        tc.BidDuration,
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			err := p.Validate()
 | 
					 | 
				
			||||||
			if tc.expectErr {
 | 
								if tc.expectErr {
 | 
				
			||||||
				require.Error(t, err)
 | 
									require.Error(t, err)
 | 
				
			||||||
			} else {
 | 
								} 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