mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-25 07:45:18 +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