add basic auction tests

This commit is contained in:
rhuairahrighairigh 2019-12-28 18:46:53 +00:00
parent ac27571d15
commit 0d72f47bc2
7 changed files with 587 additions and 525 deletions

View File

@ -61,7 +61,7 @@ var (
supply.AppModuleBasic{},
auction.AppModuleBasic{},
cdp.AppModuleBasic{},
liquidator.AppModuleBasic{},
//liquidator.AppModuleBasic{},
pricefeed.AppModuleBasic{},
)
@ -74,6 +74,8 @@ var (
staking.NotBondedPoolName: {supply.Burner, supply.Staking},
gov.ModuleName: {supply.Burner},
validatorvesting.ModuleName: {supply.Burner},
auction.ModuleName: nil,
liquidator.ModuleName: {supply.Minter, supply.Burner},
}
)
@ -238,7 +240,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
app.auctionKeeper = auction.NewKeeper(
app.cdc,
keys[auction.StoreKey],
app.supplyKeeper, // CDP keeper standing in for bank
app.supplyKeeper,
auctionSubspace)
// app.liquidatorKeeper = liquidator.NewKeeper(
// app.cdc,
@ -269,7 +271,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
validatorvesting.NewAppModule(app.vvKeeper, app.accountKeeper),
auction.NewAppModule(app.auctionKeeper),
cdp.NewAppModule(app.cdpKeeper, app.pricefeedKeeper),
liquidator.NewAppModule(app.liquidatorKeeper),
//liquidator.NewAppModule(app.liquidatorKeeper),
pricefeed.NewAppModule(app.pricefeedKeeper),
)
@ -289,7 +291,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
auth.ModuleName, validatorvesting.ModuleName, distr.ModuleName,
staking.ModuleName, bank.ModuleName, slashing.ModuleName,
gov.ModuleName, mint.ModuleName, supply.ModuleName, crisis.ModuleName, genutil.ModuleName,
pricefeed.ModuleName, cdp.ModuleName, auction.ModuleName, liquidator.ModuleName, // TODO is this order ok?
pricefeed.ModuleName, cdp.ModuleName, auction.ModuleName, //liquidator.ModuleName, // TODO is this order ok?
)
app.mm.RegisterInvariants(&app.crisisKeeper)

View File

@ -20,7 +20,7 @@ func (k Keeper) StartForwardAuction(ctx sdk.Context, seller string, lot sdk.Coin
return 0, err
}
// store the auction
auctionID, err := k.storeNewAuction(ctx, auction) // TODO does this need to be a pointer to satisfy the interface?
auctionID, err := k.storeNewAuction(ctx, auction)
if err != nil {
return 0, err
}
@ -38,7 +38,7 @@ func (k Keeper) StartReverseAuction(ctx sdk.Context, buyer string, bid sdk.Coin,
return 0, sdk.ErrInternal("module does not have minting permissions")
}
// store the auction
auctionID, err := k.storeNewAuction(ctx, &auction)
auctionID, err := k.storeNewAuction(ctx, auction)
if err != nil {
return 0, err
}
@ -51,12 +51,12 @@ func (k Keeper) StartForwardReverseAuction(ctx sdk.Context, seller string, lot s
auction := types.NewForwardReverseAuction(seller, lot, ctx.BlockTime().Add(types.DefaultMaxAuctionDuration), maxBid, otherPerson)
// take coins from module account
err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.Coins{lot})
err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot))
if err != nil {
return 0, err
}
// store the auction
auctionID, err := k.storeNewAuction(ctx, &auction)
auctionID, err := k.storeNewAuction(ctx, auction)
if err != nil {
return 0, err
}
@ -64,6 +64,7 @@ func (k Keeper) StartForwardReverseAuction(ctx sdk.Context, seller string, lot s
}
// PlaceBid places a bid on any auction.
// TODO passing bid and lot is weird when only one needed
func (k Keeper) PlaceBid(ctx sdk.Context, auctionID types.ID, bidder sdk.AccAddress, bid sdk.Coin, lot sdk.Coin) sdk.Error {
// get auction from store
@ -72,11 +73,18 @@ func (k Keeper) PlaceBid(ctx sdk.Context, auctionID types.ID, bidder sdk.AccAddr
return sdk.ErrInternal("auction doesn't exist")
}
// check end time
// validate
if ctx.BlockTime().After(auction.GetEndTime()) {
return sdk.ErrInternal("auction has closed")
}
if auction.GetBid().Denom != bid.Denom {
return sdk.ErrInternal("bid has incorrect denom")
}
if auction.GetLot().Denom != lot.Denom {
return sdk.ErrInternal("lot has incorrect denom")
}
// place bid
var err sdk.Error
var a types.Auction
switch auc := auction.(type) {
@ -124,7 +132,7 @@ func (k Keeper) PlaceBidForward(ctx sdk.Context, a types.ForwardAuction, bidder
if err != nil {
return a, err
}
err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, bidder, sdk.NewCoins(bidAmtToReturn))
err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.Bidder, sdk.NewCoins(bidAmtToReturn))
if err != nil {
return a, err
}
@ -185,7 +193,7 @@ func (k Keeper) PlaceBidForwardReverse(ctx sdk.Context, a types.ForwardReverseAu
if err != nil {
return a, err
}
err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, bidder, sdk.NewCoins(bidAmtToReturn))
err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.Bidder, sdk.NewCoins(bidAmtToReturn))
if err != nil {
return a, err
}
@ -205,7 +213,7 @@ func (k Keeper) PlaceBidForwardReverse(ctx sdk.Context, a types.ForwardReverseAu
// increment timeout
a.EndTime = earliestTime(ctx.BlockTime().Add(types.DefaultMaxBidDuration), a.MaxEndTime)
return types.ForwardReverseAuction{}, nil
return a, nil
}
func (k Keeper) PlaceBidReverse(ctx sdk.Context, a types.ReverseAuction, bidder sdk.AccAddress, lot sdk.Coin) (types.ReverseAuction, sdk.Error) {
// Validate New Bid
@ -228,7 +236,7 @@ func (k Keeper) PlaceBidReverse(ctx sdk.Context, a types.ReverseAuction, bidder
if err != nil {
return a, err
}
err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, bidder, sdk.NewCoins(bidAmtToReturn))
err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.Bidder, sdk.NewCoins(bidAmtToReturn))
if err != nil {
return a, err
}
@ -297,7 +305,11 @@ func (k Keeper) PayoutAuctionLot(ctx sdk.Context, a types.Auction) sdk.Error {
return nil
}
// FIXME stand in func for compiler
// earliestTime returns the earliest of two times.
func earliestTime(t1, t2 time.Time) time.Time {
if t1.Before(t2) {
return t1
} else {
return t2 // also returned if times are equal
}
}

View File

@ -0,0 +1,145 @@
package keeper_test
import (
"testing"
"github.com/cosmos/cosmos-sdk/x/auth"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
"github.com/cosmos/cosmos-sdk/x/supply"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/auction/types"
"github.com/kava-labs/kava/x/liquidator"
)
func TestForwardAuctionBasic(t *testing.T) {
// Setup
_, addrs := app.GeneratePrivKeyAddressPairs(1)
buyer := addrs[0]
sellerModName := liquidator.ModuleName
sellerAddr := supply.NewModuleAddress(sellerModName)
tApp := app.NewTestApp()
sellerAcc := supply.NewEmptyModuleAccount(sellerModName, supply.Burner) // forward auctions burn proceeds
require.NoError(t, sellerAcc.SetCoins(cs(c("token1", 100), c("token2", 100))))
tApp.InitializeFromGenesisStates(
NewAuthGenStateFromAccs(authexported.GenesisAccounts{
auth.NewBaseAccount(buyer, cs(c("token1", 100), c("token2", 100)), nil, 0, 0),
sellerAcc,
}),
)
ctx := tApp.NewContext(false, abci.Header{})
keeper := tApp.GetAuctionKeeper()
// Create an auction (lot: 20 token1, initialBid: 0 token2)
auctionID, err := keeper.StartForwardAuction(ctx, sellerModName, c("token1", 20), "token2") // lot, bid denom
require.NoError(t, err)
// Check seller's coins have decreased
tApp.CheckBalance(t, ctx, sellerAddr, cs(c("token1", 80), c("token2", 100)))
// PlaceBid (bid: 10 token, lot: same as starting)
require.NoError(t, keeper.PlaceBid(ctx, auctionID, buyer, c("token2", 10), c("token1", 20))) // bid, lot
// Check buyer's coins have decreased
tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 90)))
// Check seller's coins have not increased (because proceeds are burned)
tApp.CheckBalance(t, ctx, sellerAddr, cs(c("token1", 80), c("token2", 100)))
// Close auction at just at auction expiry time
ctx = ctx.WithBlockTime(ctx.BlockTime().Add(types.DefaultMaxBidDuration))
require.NoError(t, keeper.CloseAuction(ctx, auctionID))
// Check buyer's coins increased
tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 120), c("token2", 90)))
}
func TestReverseAuctionBasic(t *testing.T) {
// Setup
_, addrs := app.GeneratePrivKeyAddressPairs(1)
seller := addrs[0]
buyerModName := liquidator.ModuleName
buyerAddr := supply.NewModuleAddress(buyerModName)
tApp := app.NewTestApp()
tApp.InitializeFromGenesisStates(
NewAuthGenStateFromAccs(authexported.GenesisAccounts{
auth.NewBaseAccount(seller, cs(c("token1", 100), c("token2", 100)), nil, 0, 0),
supply.NewEmptyModuleAccount(buyerModName, supply.Minter), // reverse auctions mint payout
}),
)
ctx := tApp.NewContext(false, abci.Header{})
keeper := tApp.GetAuctionKeeper()
// Start auction
auctionID, err := keeper.StartReverseAuction(ctx, buyerModName, c("token1", 20), c("token2", 99999)) // buyer, bid, initialLot
require.NoError(t, err)
// Check buyer's coins have not decreased, as lot is minted at the end
tApp.CheckBalance(t, ctx, buyerAddr, nil) // zero coins
// Place a bid
require.NoError(t, keeper.PlaceBid(ctx, 0, seller, c("token1", 20), c("token2", 10))) // bid, lot
// Check seller's coins have decreased
tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 100)))
// Check buyer's coins have increased
tApp.CheckBalance(t, ctx, buyerAddr, cs(c("token1", 20)))
// Close auction at just after auction expiry
ctx = ctx.WithBlockTime(ctx.BlockTime().Add(types.DefaultMaxBidDuration))
require.NoError(t, keeper.CloseAuction(ctx, auctionID))
// Check seller's coins increased
tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 110)))
}
func TestForwardReverseAuctionBasic(t *testing.T) {
// Setup
_, addrs := app.GeneratePrivKeyAddressPairs(2)
buyer := addrs[0]
recipient := addrs[1]
sellerModName := liquidator.ModuleName
sellerAddr := supply.NewModuleAddress(sellerModName)
tApp := app.NewTestApp()
sellerAcc := supply.NewEmptyModuleAccount(sellerModName)
require.NoError(t, sellerAcc.SetCoins(cs(c("token1", 100), c("token2", 100))))
tApp.InitializeFromGenesisStates(
NewAuthGenStateFromAccs(authexported.GenesisAccounts{
auth.NewBaseAccount(buyer, cs(c("token1", 100), c("token2", 100)), nil, 0, 0),
auth.NewBaseAccount(recipient, cs(c("token1", 100), c("token2", 100)), nil, 0, 0),
sellerAcc,
}),
)
ctx := tApp.NewContext(false, abci.Header{})
keeper := tApp.GetAuctionKeeper()
// Start auction
auctionID, err := keeper.StartForwardReverseAuction(ctx, sellerModName, c("token1", 20), c("token2", 50), recipient) // seller, lot, maxBid, otherPerson
require.NoError(t, err)
// Check seller's coins have decreased
tApp.CheckBalance(t, ctx, sellerAddr, cs(c("token1", 80), c("token2", 100)))
// Place a forward bid
require.NoError(t, keeper.PlaceBid(ctx, 0, buyer, c("token2", 10), c("token1", 20))) // bid, lot
// Check bidder's coins have decreased
tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 90)))
// Check seller's coins have increased
tApp.CheckBalance(t, ctx, sellerAddr, cs(c("token1", 80), c("token2", 110)))
// Check recipient has not received coins
tApp.CheckBalance(t, ctx, recipient, cs(c("token1", 100), c("token2", 100)))
// Place a reverse bid
require.NoError(t, keeper.PlaceBid(ctx, 0, buyer, c("token2", 50), c("token1", 15))) // bid, lot
// Check bidder's coins have decreased
tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 50)))
// Check seller's coins have increased
tApp.CheckBalance(t, ctx, sellerAddr, cs(c("token1", 80), c("token2", 150)))
// Check "recipient" has received coins
tApp.CheckBalance(t, ctx, recipient, cs(c("token1", 105), c("token2", 100)))
// Close auction at just after auction expiry
ctx = ctx.WithBlockTime(ctx.BlockTime().Add(types.DefaultMaxBidDuration))
require.NoError(t, keeper.CloseAuction(ctx, auctionID))
// Check buyer's coins increased
tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 115), c("token2", 50)))
}

View File

@ -0,0 +1,17 @@
package keeper_test
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
"github.com/kava-labs/kava/app"
)
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) }
func NewAuthGenStateFromAccs(accounts authexported.GenesisAccounts) app.GenesisState {
authGenesis := auth.NewGenesisState(auth.DefaultParams(), accounts)
return app.GenesisState{auth.ModuleName: auth.ModuleCdc.MustMarshalJSON(authGenesis)}
}

View File

@ -13,128 +13,22 @@ import (
"github.com/kava-labs/kava/x/auction/types"
)
// func TestKeeper_ForwardAuction(t *testing.T) {
// // Setup
// _, addrs := app.GeneratePrivKeyAddressPairs(2)
// seller := addrs[0]
// buyer := addrs[1]
// tApp := app.NewTestApp()
// tApp.InitializeFromGenesisStates(
// app.NewAuthGenState(addrs, []sdk.Coins{cs(c("token1", 100), c("token2", 100)), cs(c("token1", 100), c("token2", 100))}),
// )
// ctx := tApp.NewContext(false, abci.Header{})
// keeper := tApp.GetAuctionKeeper()
// // Create an auction (lot: 20 t1, initialBid: 0 t2)
// auctionID, err := keeper.StartForwardAuction(ctx, seller, c("token1", 20), c("token2", 0)) // lot, initialBid
// require.NoError(t, err)
// // Check seller's coins have decreased
// tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 100)))
// // PlaceBid (bid: 10 t2, lot: same as starting)
// require.NoError(t, keeper.PlaceBid(ctx, 0, buyer, c("token2", 10), c("token1", 20))) // bid, lot
// // Check buyer's coins have decreased
// tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 90)))
// // Check seller's coins have increased
// tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 110)))
// // Close auction at just after auction expiry
// ctx = ctx.WithBlockHeight(int64(types.DefaultMaxBidDuration))
// require.NoError(t, keeper.CloseAuction(ctx, auctionID))
// // Check buyer's coins increased
// tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 120), c("token2", 90)))
// }
// func TestKeeper_ReverseAuction(t *testing.T) {
// // Setup
// _, addrs := app.GeneratePrivKeyAddressPairs(2)
// seller := addrs[0]
// buyer := addrs[1]
// tApp := app.NewTestApp()
// tApp.InitializeFromGenesisStates(
// app.NewAuthGenState(addrs, []sdk.Coins{cs(c("token1", 100), c("token2", 100)), cs(c("token1", 100), c("token2", 100))}),
// )
// ctx := tApp.NewContext(false, abci.Header{})
// keeper := tApp.GetAuctionKeeper()
// // Start auction
// auctionID, err := keeper.StartReverseAuction(ctx, buyer, c("token1", 20), c("token2", 99)) // buyer, bid, initialLot
// require.NoError(t, err)
// // Check buyer's coins have decreased
// tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 1)))
// // Place a bid
// require.NoError(t, keeper.PlaceBid(ctx, 0, seller, c("token1", 20), c("token2", 10))) // bid, lot
// // Check seller's coins have decreased
// tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 100)))
// // Check buyer's coins have increased
// tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 120), c("token2", 90)))
// // Close auction at just after auction expiry
// ctx = ctx.WithBlockHeight(int64(types.DefaultMaxBidDuration))
// require.NoError(t, keeper.CloseAuction(ctx, auctionID))
// // Check seller's coins increased
// tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 110)))
// }
// func TestKeeper_ForwardReverseAuction(t *testing.T) {
// // Setup
// _, addrs := app.GeneratePrivKeyAddressPairs(3)
// seller := addrs[0]
// buyer := addrs[1]
// recipient := addrs[2]
// tApp := app.NewTestApp()
// tApp.InitializeFromGenesisStates(
// app.NewAuthGenState(addrs, []sdk.Coins{cs(c("token1", 100), c("token2", 100)), cs(c("token1", 100), c("token2", 100)), cs(c("token1", 100), c("token2", 100))}),
// )
// ctx := tApp.NewContext(false, abci.Header{})
// keeper := tApp.GetAuctionKeeper()
// // Start auction
// auctionID, err := keeper.StartForwardReverseAuction(ctx, seller, c("token1", 20), c("token2", 50), recipient) // seller, lot, maxBid, otherPerson
// require.NoError(t, err)
// // Check seller's coins have decreased
// tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 100)))
// // Place a bid
// require.NoError(t, keeper.PlaceBid(ctx, 0, buyer, c("token2", 50), c("token1", 15))) // bid, lot
// // Check bidder's coins have decreased
// tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 50)))
// // Check seller's coins have increased
// tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 150)))
// // Check "recipient" has received coins
// tApp.CheckBalance(t, ctx, recipient, cs(c("token1", 105), c("token2", 100)))
// // Close auction at just after auction expiry
// ctx = ctx.WithBlockHeight(int64(types.DefaultMaxBidDuration))
// require.NoError(t, keeper.CloseAuction(ctx, auctionID))
// // Check buyer's coins increased
// tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 115), c("token2", 50)))
// }
func SetGetDeleteAuction(t *testing.T) {
// setup keeper, create auction
tApp := app.NewTestApp()
keeper := tApp.GetAuctionKeeper()
ctx := tApp.NewContext(true, abci.Header{})
someTime := time.Date(43, time.January, 1, 0, 0, 0, 0, time.UTC) // need to specify UTC as tz info is lost on unmarshal
auction := types.NewForwardAuction("some_module", c("usdx", 100), "kava", someTime)
id := types.ID(5)
auction.SetID(id)
auction := types.NewForwardAuction("some_module", c("usdx", 100), "kava", someTime).WithID(id)
// write and read from store
keeper.SetAuction(ctx, &auction)
keeper.SetAuction(ctx, auction)
readAuction, found := keeper.GetAuction(ctx, id)
// check before and after match
require.True(t, found)
require.Equal(t, &auction, readAuction)
require.Equal(t, auction, readAuction)
// check auction is in queue
// iter := keeper.GetQueueIterator(ctx, 100000)
// require.Equal(t, 1, len(convertIteratorToSlice(keeper, iter)))
@ -245,6 +139,3 @@ func convertIteratorToSlice(keeper keeper.Keeper, iterator sdk.Iterator) []types
}
return queue
}
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) }

View File

@ -37,6 +37,7 @@ type Auction interface {
GetID() ID
WithID(ID) Auction
GetBidder() sdk.AccAddress
GetBid() sdk.Coin
GetLot() sdk.Coin
GetEndTime() time.Time
}
@ -44,7 +45,7 @@ type Auction interface {
// BaseAuction type shared by all Auctions
type BaseAuction struct {
ID ID
Initiator string // Module who starts the auction. Giving away Lot (aka seller in a forward auction). Restricted to being a module account name rather than any account.
Initiator string // Module that starts the auction. Giving away Lot (aka seller in a forward auction). Restricted to being a module account name rather than any account.
Lot sdk.Coin // Amount of coins up being given by initiator (FA - amount for sale by seller, RA - cost of good by buyer (bid))
Bidder sdk.AccAddress // Person who bids in the auction. Receiver of Lot. (aka buyer in forward auction, seller in RA)
Bid sdk.Coin // Amount of coins being given by the bidder (FA - bid, RA - amount being sold)
@ -58,6 +59,9 @@ func (a BaseAuction) GetID() ID { return a.ID }
// GetBid getter for auction bid
func (a BaseAuction) GetBidder() sdk.AccAddress { return a.Bidder }
// GetBid getter for auction lot
func (a BaseAuction) GetBid() sdk.Coin { return a.Bid }
// GetLot getter for auction lot
func (a BaseAuction) GetLot() sdk.Coin { return a.Lot }
@ -83,7 +87,7 @@ type ForwardAuction struct {
BaseAuction
}
// WithID returns an auction wtih the ID set
// WithID returns an auction with the ID set
func (a ForwardAuction) WithID(id ID) Auction { a.ID = id; return a }
// NewForwardAuction creates a new forward auction
@ -97,7 +101,6 @@ func NewForwardAuction(seller string, lot sdk.Coin, bidDenom string, endTime tim
EndTime: endTime,
MaxEndTime: endTime,
}}
// output := BankOutput{seller, lot}
return auction
}
@ -106,7 +109,7 @@ type ReverseAuction struct {
BaseAuction
}
// WithID returns an auction wtih the ID set
// WithID returns an auction with the ID set
func (a ReverseAuction) WithID(id ID) Auction { a.ID = id; return a }
// NewReverseAuction creates a new reverse auction
@ -134,7 +137,7 @@ type ForwardReverseAuction struct {
OtherPerson sdk.AccAddress // TODO rename, this is normally the original CDP owner, will have to be updated to account for deposits
}
// WithID returns an auction wtih the ID set
// WithID returns an auction with the ID set
func (a ForwardReverseAuction) WithID(id ID) Auction { a.ID = id; return a }
func (a ForwardReverseAuction) String() string {
@ -167,6 +170,5 @@ func NewForwardReverseAuction(seller string, lot sdk.Coin, EndTime time.Time, ma
MaxBid: maxBid,
OtherPerson: otherPerson,
}
//output := BankOutput{seller, lot}
return auction
}

View File

@ -1,403 +1,396 @@
package types
import (
"testing"
// // TODO can this be less verbose? Should PlaceBid() be split into smaller functions?
// // It would be possible to combine all auction tests into one test runner.
// func TestForwardAuction_PlaceBid(t *testing.T) {
// seller := sdk.AccAddress([]byte("a_seller"))
// buyer1 := sdk.AccAddress([]byte("buyer1"))
// buyer2 := sdk.AccAddress([]byte("buyer2"))
// end := EndTime(10000)
// now := EndTime(10)
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
// type args struct {
// currentBlockHeight EndTime
// bidder sdk.AccAddress
// lot sdk.Coin
// bid sdk.Coin
// }
// tests := []struct {
// name string
// auction ForwardAuction
// args args
// expectedOutputs []BankOutput
// expectedInputs []BankInput
// expectedEndTime EndTime
// expectedBidder sdk.AccAddress
// expectedBid sdk.Coin
// expectpass bool
// }{
// {
// "normal",
// ForwardAuction{BaseAuction{
// Initiator: seller,
// Lot: c("usdx", 100),
// Bidder: buyer1,
// Bid: c("kava", 6),
// EndTime: end,
// MaxEndTime: end,
// }},
// args{now, buyer2, c("usdx", 100), c("kava", 10)},
// []BankOutput{{buyer2, c("kava", 10)}},
// []BankInput{{buyer1, c("kava", 6)}, {seller, c("kava", 4)}},
// now + DefaultMaxBidDuration,
// buyer2,
// c("kava", 10),
// true,
// },
// {
// "lowBid",
// ForwardAuction{BaseAuction{
// Initiator: seller,
// Lot: c("usdx", 100),
// Bidder: buyer1,
// Bid: c("kava", 6),
// EndTime: end,
// MaxEndTime: end,
// }},
// args{now, buyer2, c("usdx", 100), c("kava", 5)},
// []BankOutput{},
// []BankInput{},
// end,
// buyer1,
// c("kava", 6),
// false,
// },
// {
// "equalBid",
// ForwardAuction{BaseAuction{
// Initiator: seller,
// Lot: c("usdx", 100),
// Bidder: buyer1,
// Bid: c("kava", 6),
// EndTime: end,
// MaxEndTime: end,
// }},
// args{now, buyer2, c("usdx", 100), c("kava", 6)},
// []BankOutput{},
// []BankInput{},
// end,
// buyer1,
// c("kava", 6),
// false,
// },
// {
// "timeout",
// ForwardAuction{BaseAuction{
// Initiator: seller,
// Lot: c("usdx", 100),
// Bidder: buyer1,
// Bid: c("kava", 6),
// EndTime: end,
// MaxEndTime: end,
// }},
// args{end + 1, buyer2, c("usdx", 100), c("kava", 10)},
// []BankOutput{},
// []BankInput{},
// end,
// buyer1,
// c("kava", 6),
// false,
// },
// {
// "hitMaxEndTime",
// ForwardAuction{BaseAuction{
// Initiator: seller,
// Lot: c("usdx", 100),
// Bidder: buyer1,
// Bid: c("kava", 6),
// EndTime: end,
// MaxEndTime: end,
// }},
// args{end - 1, buyer2, c("usdx", 100), c("kava", 10)},
// []BankOutput{{buyer2, c("kava", 10)}},
// []BankInput{{buyer1, c("kava", 6)}, {seller, c("kava", 4)}},
// end, // end time should be capped at MaxEndTime
// buyer2,
// c("kava", 10),
// true,
// },
// }
// for _, tc := range tests {
// t.Run(tc.name, func(t *testing.T) {
// // update auction and return in/outputs
// outputs, inputs, err := tc.auction.PlaceBid(tc.args.currentBlockHeight, tc.args.bidder, tc.args.lot, tc.args.bid)
// TODO can this be less verbose? Should PlaceBid() be split into smaller functions?
// It would be possible to combine all auction tests into one test runner.
func TestForwardAuction_PlaceBid(t *testing.T) {
seller := sdk.AccAddress([]byte("a_seller"))
buyer1 := sdk.AccAddress([]byte("buyer1"))
buyer2 := sdk.AccAddress([]byte("buyer2"))
end := EndTime(10000)
now := EndTime(10)
// // check for err
// if tc.expectpass {
// require.Nil(t, err)
// } else {
// require.NotNil(t, err)
// }
// // check for correct in/outputs
// require.Equal(t, tc.expectedOutputs, outputs)
// require.Equal(t, tc.expectedInputs, inputs)
// // check for correct EndTime, bidder, bid
// require.Equal(t, tc.expectedEndTime, tc.auction.EndTime)
// require.Equal(t, tc.expectedBidder, tc.auction.Bidder)
// require.Equal(t, tc.expectedBid, tc.auction.Bid)
// })
// }
// }
type args struct {
currentBlockHeight EndTime
bidder sdk.AccAddress
lot sdk.Coin
bid sdk.Coin
}
tests := []struct {
name string
auction ForwardAuction
args args
expectedOutputs []BankOutput
expectedInputs []BankInput
expectedEndTime EndTime
expectedBidder sdk.AccAddress
expectedBid sdk.Coin
expectpass bool
}{
{
"normal",
ForwardAuction{BaseAuction{
Initiator: seller,
Lot: c("usdx", 100),
Bidder: buyer1,
Bid: c("kava", 6),
EndTime: end,
MaxEndTime: end,
}},
args{now, buyer2, c("usdx", 100), c("kava", 10)},
[]BankOutput{{buyer2, c("kava", 10)}},
[]BankInput{{buyer1, c("kava", 6)}, {seller, c("kava", 4)}},
now + DefaultMaxBidDuration,
buyer2,
c("kava", 10),
true,
},
{
"lowBid",
ForwardAuction{BaseAuction{
Initiator: seller,
Lot: c("usdx", 100),
Bidder: buyer1,
Bid: c("kava", 6),
EndTime: end,
MaxEndTime: end,
}},
args{now, buyer2, c("usdx", 100), c("kava", 5)},
[]BankOutput{},
[]BankInput{},
end,
buyer1,
c("kava", 6),
false,
},
{
"equalBid",
ForwardAuction{BaseAuction{
Initiator: seller,
Lot: c("usdx", 100),
Bidder: buyer1,
Bid: c("kava", 6),
EndTime: end,
MaxEndTime: end,
}},
args{now, buyer2, c("usdx", 100), c("kava", 6)},
[]BankOutput{},
[]BankInput{},
end,
buyer1,
c("kava", 6),
false,
},
{
"timeout",
ForwardAuction{BaseAuction{
Initiator: seller,
Lot: c("usdx", 100),
Bidder: buyer1,
Bid: c("kava", 6),
EndTime: end,
MaxEndTime: end,
}},
args{end + 1, buyer2, c("usdx", 100), c("kava", 10)},
[]BankOutput{},
[]BankInput{},
end,
buyer1,
c("kava", 6),
false,
},
{
"hitMaxEndTime",
ForwardAuction{BaseAuction{
Initiator: seller,
Lot: c("usdx", 100),
Bidder: buyer1,
Bid: c("kava", 6),
EndTime: end,
MaxEndTime: end,
}},
args{end - 1, buyer2, c("usdx", 100), c("kava", 10)},
[]BankOutput{{buyer2, c("kava", 10)}},
[]BankInput{{buyer1, c("kava", 6)}, {seller, c("kava", 4)}},
end, // end time should be capped at MaxEndTime
buyer2,
c("kava", 10),
true,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// update auction and return in/outputs
outputs, inputs, err := tc.auction.PlaceBid(tc.args.currentBlockHeight, tc.args.bidder, tc.args.lot, tc.args.bid)
// func TestReverseAuction_PlaceBid(t *testing.T) {
// buyer := sdk.AccAddress([]byte("a_buyer"))
// seller1 := sdk.AccAddress([]byte("seller1"))
// seller2 := sdk.AccAddress([]byte("seller2"))
// end := EndTime(10000)
// now := EndTime(10)
// check for err
if tc.expectpass {
require.Nil(t, err)
} else {
require.NotNil(t, err)
}
// check for correct in/outputs
require.Equal(t, tc.expectedOutputs, outputs)
require.Equal(t, tc.expectedInputs, inputs)
// check for correct EndTime, bidder, bid
require.Equal(t, tc.expectedEndTime, tc.auction.EndTime)
require.Equal(t, tc.expectedBidder, tc.auction.Bidder)
require.Equal(t, tc.expectedBid, tc.auction.Bid)
})
}
}
// type args struct {
// currentBlockHeight EndTime
// bidder sdk.AccAddress
// lot sdk.Coin
// bid sdk.Coin
// }
// tests := []struct {
// name string
// auction ReverseAuction
// args args
// expectedOutputs []BankOutput
// expectedInputs []BankInput
// expectedEndTime EndTime
// expectedBidder sdk.AccAddress
// expectedLot sdk.Coin
// expectpass bool
// }{
// {
// "normal",
// ReverseAuction{BaseAuction{
// Initiator: buyer,
// Lot: c("kava", 10),
// Bidder: seller1,
// Bid: c("usdx", 100),
// EndTime: end,
// MaxEndTime: end,
// }},
// args{now, seller2, c("kava", 9), c("usdx", 100)},
// []BankOutput{{seller2, c("usdx", 100)}},
// []BankInput{{seller1, c("usdx", 100)}, {buyer, c("kava", 1)}},
// now + DefaultMaxBidDuration,
// seller2,
// c("kava", 9),
// true,
// },
// {
// "highBid",
// ReverseAuction{BaseAuction{
// Initiator: buyer,
// Lot: c("kava", 10),
// Bidder: seller1,
// Bid: c("usdx", 100),
// EndTime: end,
// MaxEndTime: end,
// }},
// args{now, seller2, c("kava", 11), c("usdx", 100)},
// []BankOutput{},
// []BankInput{},
// end,
// seller1,
// c("kava", 10),
// false,
// },
// {
// "equalBid",
// ReverseAuction{BaseAuction{
// Initiator: buyer,
// Lot: c("kava", 10),
// Bidder: seller1,
// Bid: c("usdx", 100),
// EndTime: end,
// MaxEndTime: end,
// }},
// args{now, seller2, c("kava", 10), c("usdx", 100)},
// []BankOutput{},
// []BankInput{},
// end,
// seller1,
// c("kava", 10),
// false,
// },
// {
// "timeout",
// ReverseAuction{BaseAuction{
// Initiator: buyer,
// Lot: c("kava", 10),
// Bidder: seller1,
// Bid: c("usdx", 100),
// EndTime: end,
// MaxEndTime: end,
// }},
// args{end + 1, seller2, c("kava", 9), c("usdx", 100)},
// []BankOutput{},
// []BankInput{},
// end,
// seller1,
// c("kava", 10),
// false,
// },
// {
// "hitMaxEndTime",
// ReverseAuction{BaseAuction{
// Initiator: buyer,
// Lot: c("kava", 10),
// Bidder: seller1,
// Bid: c("usdx", 100),
// EndTime: end,
// MaxEndTime: end,
// }},
// args{end - 1, seller2, c("kava", 9), c("usdx", 100)},
// []BankOutput{{seller2, c("usdx", 100)}},
// []BankInput{{seller1, c("usdx", 100)}, {buyer, c("kava", 1)}},
// end, // end time should be capped at MaxEndTime
// seller2,
// c("kava", 9),
// true,
// },
// }
// for _, tc := range tests {
// t.Run(tc.name, func(t *testing.T) {
// // update auction and return in/outputs
// outputs, inputs, err := tc.auction.PlaceBid(tc.args.currentBlockHeight, tc.args.bidder, tc.args.lot, tc.args.bid)
func TestReverseAuction_PlaceBid(t *testing.T) {
buyer := sdk.AccAddress([]byte("a_buyer"))
seller1 := sdk.AccAddress([]byte("seller1"))
seller2 := sdk.AccAddress([]byte("seller2"))
end := EndTime(10000)
now := EndTime(10)
// // check for err
// if tc.expectpass {
// require.Nil(t, err)
// } else {
// require.NotNil(t, err)
// }
// // check for correct in/outputs
// require.Equal(t, tc.expectedOutputs, outputs)
// require.Equal(t, tc.expectedInputs, inputs)
// // check for correct EndTime, bidder, bid
// require.Equal(t, tc.expectedEndTime, tc.auction.EndTime)
// require.Equal(t, tc.expectedBidder, tc.auction.Bidder)
// require.Equal(t, tc.expectedLot, tc.auction.Lot)
// })
// }
// }
type args struct {
currentBlockHeight EndTime
bidder sdk.AccAddress
lot sdk.Coin
bid sdk.Coin
}
tests := []struct {
name string
auction ReverseAuction
args args
expectedOutputs []BankOutput
expectedInputs []BankInput
expectedEndTime EndTime
expectedBidder sdk.AccAddress
expectedLot sdk.Coin
expectpass bool
}{
{
"normal",
ReverseAuction{BaseAuction{
Initiator: buyer,
Lot: c("kava", 10),
Bidder: seller1,
Bid: c("usdx", 100),
EndTime: end,
MaxEndTime: end,
}},
args{now, seller2, c("kava", 9), c("usdx", 100)},
[]BankOutput{{seller2, c("usdx", 100)}},
[]BankInput{{seller1, c("usdx", 100)}, {buyer, c("kava", 1)}},
now + DefaultMaxBidDuration,
seller2,
c("kava", 9),
true,
},
{
"highBid",
ReverseAuction{BaseAuction{
Initiator: buyer,
Lot: c("kava", 10),
Bidder: seller1,
Bid: c("usdx", 100),
EndTime: end,
MaxEndTime: end,
}},
args{now, seller2, c("kava", 11), c("usdx", 100)},
[]BankOutput{},
[]BankInput{},
end,
seller1,
c("kava", 10),
false,
},
{
"equalBid",
ReverseAuction{BaseAuction{
Initiator: buyer,
Lot: c("kava", 10),
Bidder: seller1,
Bid: c("usdx", 100),
EndTime: end,
MaxEndTime: end,
}},
args{now, seller2, c("kava", 10), c("usdx", 100)},
[]BankOutput{},
[]BankInput{},
end,
seller1,
c("kava", 10),
false,
},
{
"timeout",
ReverseAuction{BaseAuction{
Initiator: buyer,
Lot: c("kava", 10),
Bidder: seller1,
Bid: c("usdx", 100),
EndTime: end,
MaxEndTime: end,
}},
args{end + 1, seller2, c("kava", 9), c("usdx", 100)},
[]BankOutput{},
[]BankInput{},
end,
seller1,
c("kava", 10),
false,
},
{
"hitMaxEndTime",
ReverseAuction{BaseAuction{
Initiator: buyer,
Lot: c("kava", 10),
Bidder: seller1,
Bid: c("usdx", 100),
EndTime: end,
MaxEndTime: end,
}},
args{end - 1, seller2, c("kava", 9), c("usdx", 100)},
[]BankOutput{{seller2, c("usdx", 100)}},
[]BankInput{{seller1, c("usdx", 100)}, {buyer, c("kava", 1)}},
end, // end time should be capped at MaxEndTime
seller2,
c("kava", 9),
true,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// update auction and return in/outputs
outputs, inputs, err := tc.auction.PlaceBid(tc.args.currentBlockHeight, tc.args.bidder, tc.args.lot, tc.args.bid)
// func TestForwardReverseAuction_PlaceBid(t *testing.T) {
// cdpOwner := sdk.AccAddress([]byte("a_cdp_owner"))
// seller := sdk.AccAddress([]byte("a_seller"))
// buyer1 := sdk.AccAddress([]byte("buyer1"))
// buyer2 := sdk.AccAddress([]byte("buyer2"))
// end := EndTime(10000)
// now := EndTime(10)
// check for err
if tc.expectpass {
require.Nil(t, err)
} else {
require.NotNil(t, err)
}
// check for correct in/outputs
require.Equal(t, tc.expectedOutputs, outputs)
require.Equal(t, tc.expectedInputs, inputs)
// check for correct EndTime, bidder, bid
require.Equal(t, tc.expectedEndTime, tc.auction.EndTime)
require.Equal(t, tc.expectedBidder, tc.auction.Bidder)
require.Equal(t, tc.expectedLot, tc.auction.Lot)
})
}
}
// type args struct {
// currentBlockHeight EndTime
// bidder sdk.AccAddress
// lot sdk.Coin
// bid sdk.Coin
// }
// tests := []struct {
// name string
// auction ForwardReverseAuction
// args args
// expectedOutputs []BankOutput
// expectedInputs []BankInput
// expectedEndTime EndTime
// expectedBidder sdk.AccAddress
// expectedLot sdk.Coin
// expectedBid sdk.Coin
// expectpass bool
// }{
// {
// "normalForwardBid",
// ForwardReverseAuction{BaseAuction: BaseAuction{
// Initiator: seller,
// Lot: c("xrp", 100),
// Bidder: buyer1,
// Bid: c("usdx", 5),
// EndTime: end,
// MaxEndTime: end},
// MaxBid: c("usdx", 10),
// OtherPerson: cdpOwner,
// },
// args{now, buyer2, c("xrp", 100), c("usdx", 6)},
// []BankOutput{{buyer2, c("usdx", 6)}},
// []BankInput{{buyer1, c("usdx", 5)}, {seller, c("usdx", 1)}},
// now + DefaultMaxBidDuration,
// buyer2,
// c("xrp", 100),
// c("usdx", 6),
// true,
// },
// {
// "normalSwitchOverBid",
// ForwardReverseAuction{BaseAuction: BaseAuction{
// Initiator: seller,
// Lot: c("xrp", 100),
// Bidder: buyer1,
// Bid: c("usdx", 5),
// EndTime: end,
// MaxEndTime: end},
// MaxBid: c("usdx", 10),
// OtherPerson: cdpOwner,
// },
// args{now, buyer2, c("xrp", 99), c("usdx", 10)},
// []BankOutput{{buyer2, c("usdx", 10)}},
// []BankInput{{buyer1, c("usdx", 5)}, {seller, c("usdx", 5)}, {cdpOwner, c("xrp", 1)}},
// now + DefaultMaxBidDuration,
// buyer2,
// c("xrp", 99),
// c("usdx", 10),
// true,
// },
// {
// "normalReverseBid",
// ForwardReverseAuction{BaseAuction: BaseAuction{
// Initiator: seller,
// Lot: c("xrp", 99),
// Bidder: buyer1,
// Bid: c("usdx", 10),
// EndTime: end,
// MaxEndTime: end},
// MaxBid: c("usdx", 10),
// OtherPerson: cdpOwner,
// },
// args{now, buyer2, c("xrp", 90), c("usdx", 10)},
// []BankOutput{{buyer2, c("usdx", 10)}},
// []BankInput{{buyer1, c("usdx", 10)}, {cdpOwner, c("xrp", 9)}},
// now + DefaultMaxBidDuration,
// buyer2,
// c("xrp", 90),
// c("usdx", 10),
// true,
// },
// // TODO more test cases
// }
// for _, tc := range tests {
// t.Run(tc.name, func(t *testing.T) {
// // update auction and return in/outputs
// outputs, inputs, err := tc.auction.PlaceBid(tc.args.currentBlockHeight, tc.args.bidder, tc.args.lot, tc.args.bid)
func TestForwardReverseAuction_PlaceBid(t *testing.T) {
cdpOwner := sdk.AccAddress([]byte("a_cdp_owner"))
seller := sdk.AccAddress([]byte("a_seller"))
buyer1 := sdk.AccAddress([]byte("buyer1"))
buyer2 := sdk.AccAddress([]byte("buyer2"))
end := EndTime(10000)
now := EndTime(10)
// // check for err
// if tc.expectpass {
// require.Nil(t, err)
// } else {
// require.NotNil(t, err)
// }
// // check for correct in/outputs
// require.Equal(t, tc.expectedOutputs, outputs)
// require.Equal(t, tc.expectedInputs, inputs)
// // check for correct EndTime, bidder, bid
// require.Equal(t, tc.expectedEndTime, tc.auction.EndTime)
// require.Equal(t, tc.expectedBidder, tc.auction.Bidder)
// require.Equal(t, tc.expectedLot, tc.auction.Lot)
// require.Equal(t, tc.expectedBid, tc.auction.Bid)
// })
// }
// }
type args struct {
currentBlockHeight EndTime
bidder sdk.AccAddress
lot sdk.Coin
bid sdk.Coin
}
tests := []struct {
name string
auction ForwardReverseAuction
args args
expectedOutputs []BankOutput
expectedInputs []BankInput
expectedEndTime EndTime
expectedBidder sdk.AccAddress
expectedLot sdk.Coin
expectedBid sdk.Coin
expectpass bool
}{
{
"normalForwardBid",
ForwardReverseAuction{BaseAuction: BaseAuction{
Initiator: seller,
Lot: c("xrp", 100),
Bidder: buyer1,
Bid: c("usdx", 5),
EndTime: end,
MaxEndTime: end},
MaxBid: c("usdx", 10),
OtherPerson: cdpOwner,
},
args{now, buyer2, c("xrp", 100), c("usdx", 6)},
[]BankOutput{{buyer2, c("usdx", 6)}},
[]BankInput{{buyer1, c("usdx", 5)}, {seller, c("usdx", 1)}},
now + DefaultMaxBidDuration,
buyer2,
c("xrp", 100),
c("usdx", 6),
true,
},
{
"normalSwitchOverBid",
ForwardReverseAuction{BaseAuction: BaseAuction{
Initiator: seller,
Lot: c("xrp", 100),
Bidder: buyer1,
Bid: c("usdx", 5),
EndTime: end,
MaxEndTime: end},
MaxBid: c("usdx", 10),
OtherPerson: cdpOwner,
},
args{now, buyer2, c("xrp", 99), c("usdx", 10)},
[]BankOutput{{buyer2, c("usdx", 10)}},
[]BankInput{{buyer1, c("usdx", 5)}, {seller, c("usdx", 5)}, {cdpOwner, c("xrp", 1)}},
now + DefaultMaxBidDuration,
buyer2,
c("xrp", 99),
c("usdx", 10),
true,
},
{
"normalReverseBid",
ForwardReverseAuction{BaseAuction: BaseAuction{
Initiator: seller,
Lot: c("xrp", 99),
Bidder: buyer1,
Bid: c("usdx", 10),
EndTime: end,
MaxEndTime: end},
MaxBid: c("usdx", 10),
OtherPerson: cdpOwner,
},
args{now, buyer2, c("xrp", 90), c("usdx", 10)},
[]BankOutput{{buyer2, c("usdx", 10)}},
[]BankInput{{buyer1, c("usdx", 10)}, {cdpOwner, c("xrp", 9)}},
now + DefaultMaxBidDuration,
buyer2,
c("xrp", 90),
c("usdx", 10),
true,
},
// TODO more test cases
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// update auction and return in/outputs
outputs, inputs, err := tc.auction.PlaceBid(tc.args.currentBlockHeight, tc.args.bidder, tc.args.lot, tc.args.bid)
// check for err
if tc.expectpass {
require.Nil(t, err)
} else {
require.NotNil(t, err)
}
// check for correct in/outputs
require.Equal(t, tc.expectedOutputs, outputs)
require.Equal(t, tc.expectedInputs, inputs)
// check for correct EndTime, bidder, bid
require.Equal(t, tc.expectedEndTime, tc.auction.EndTime)
require.Equal(t, tc.expectedBidder, tc.auction.Bidder)
require.Equal(t, tc.expectedLot, tc.auction.Lot)
require.Equal(t, tc.expectedBid, tc.auction.Bid)
})
}
}
// defined to avoid cluttering test cases with long function name
func c(denom string, amount int64) sdk.Coin {
return sdk.NewInt64Coin(denom, amount)
}
// // defined to avoid cluttering test cases with long function name
// func c(denom string, amount int64) sdk.Coin {
// return sdk.NewInt64Coin(denom, amount)
// }