Auction rest fixes (#361)

* auction query fixes

* minor formating tweaks

* add phase info to debt & surplus auctions

* add base auction struct tags

* use module name in querier paths

* update rest tx endoint to use http body

* improve invalid coins error messages

* add rest examples

* align starting auction ID with gov and cdp

* fix cdp test broken by auction ID change

* fix all tests broken by ID change
This commit is contained in:
Ruaridh 2020-02-03 15:54:00 +00:00 committed by GitHub
parent 31e185c632
commit bbc5d3b7a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 202 additions and 106 deletions

View File

@ -0,0 +1,16 @@
{
"base_req": {
"from": "kava1xy7hrjy9r0algz9w3gzm8u6mrpq97kwta747gj",
"memo": "arbitrary text",
"chain_id": "testing",
"account_number": "0",
"sequence": "2",
"gas": "500000",
"gas_adjustment": "1.0",
"simulate": false
},
"amount": {
"denom": "usdx",
"amount": "100000000"
}
}

View File

@ -0,0 +1,32 @@
{
"type": "cosmos-sdk/StdTx",
"value": {
"msg": [
{
"type": "auction/MsgPlaceBid",
"value": {
"auction_id": "1",
"bidder": "kava1xy7hrjy9r0algz9w3gzm8u6mrpq97kwta747gj",
"amount": {
"denom": "usdx",
"amount": "100000000"
}
}
}
],
"fee": {
"amount": [],
"gas": "500000"
},
"signatures": [
{
"pub_key": {
"type": "tendermint/PubKeySecp256k1",
"value": "AsBYqm9S7cjIBdG6N/xzAGuEizTt2S2CJuM1FCsgta7u"
},
"signature": "O3zsB8P61SN7/5C+TNfO9hMaFYWV6hjr2aVigN0GrckR2PQGZhpyEZ03P71A9uK7DFLawzvAHDZRqQu833lAnA=="
}
],
"memo": "arbitrary text"
}
}

View File

@ -0,0 +1,24 @@
{
"type": "cosmos-sdk/StdTx",
"value": {
"msg": [
{
"type": "auction/MsgPlaceBid",
"value": {
"auction_id": "1",
"bidder": "kava1xy7hrjy9r0algz9w3gzm8u6mrpq97kwta747gj",
"amount": {
"denom": "usdx",
"amount": "100000000"
}
}
}
],
"fee": {
"amount": [],
"gas": "500000"
},
"signatures": null,
"memo": "arbitrary text"
}
}

View File

@ -0,0 +1,32 @@
{
"tx": {
"msg": [
{
"type": "auction/MsgPlaceBid",
"value": {
"auction_id": "1",
"bidder": "kava1xy7hrjy9r0algz9w3gzm8u6mrpq97kwta747gj",
"amount": {
"denom": "usdx",
"amount": "100000000"
}
}
}
],
"fee": {
"amount": [],
"gas": "500000"
},
"signatures": [
{
"pub_key": {
"type": "tendermint/PubKeySecp256k1",
"value": "AsBYqm9S7cjIBdG6N/xzAGuEizTt2S2CJuM1FCsgta7u"
},
"signature": "O3zsB8P61SN7/5C+TNfO9hMaFYWV6hjr2aVigN0GrckR2PQGZhpyEZ03P71A9uK7DFLawzvAHDZRqQu833lAnA=="
}
],
"memo": "arbitrary text"
},
"mode": "block"
}

View File

@ -31,6 +31,7 @@ const (
DefaultMaxAuctionDuration = types.DefaultMaxAuctionDuration DefaultMaxAuctionDuration = types.DefaultMaxAuctionDuration
DefaultBidDuration = types.DefaultBidDuration DefaultBidDuration = types.DefaultBidDuration
QueryGetAuction = types.QueryGetAuction QueryGetAuction = types.QueryGetAuction
DefaultNextAuctionID = types.DefaultNextAuctionID
) )
var ( var (

View File

@ -85,7 +85,7 @@ func QueryGetAuctionsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
var auctions types.Auctions var auctions types.Auctions
cdc.MustUnmarshalJSON(res, &auctions) cdc.MustUnmarshalJSON(res, &auctions)
var auctionsWithPhase []types.AuctionWithPhase auctionsWithPhase := []types.AuctionWithPhase{} // using empty slice so json returns [] instead of null when there's no auctions
for _, a := range auctions { for _, a := range auctions {
auctionsWithPhase = append(auctionsWithPhase, types.NewAuctionWithPhase(a)) auctionsWithPhase = append(auctionsWithPhase, types.NewAuctionWithPhase(a))
} }

View File

@ -12,12 +12,12 @@ import (
"github.com/kava-labs/kava/x/auction/types" "github.com/kava-labs/kava/x/auction/types"
) )
const RestAuctionID = "auction-id" const restAuctionID = "auction-id"
func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc(fmt.Sprintf("/auction/auctions/{%s}", RestAuctionID), queryAuctionHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/{%s}/auctions", types.ModuleName), queryAuctionsHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/auction/auctions", queryAuctionsHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/{%s}/auctions/{%s}", types.ModuleName, restAuctionID), queryAuctionHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/auction/parameters", getParamsHandlerFn(cliCtx)).Methods("GET") r.HandleFunc(fmt.Sprintf("/{%s}/parameters", types.ModuleName), getParamsHandlerFn(cliCtx)).Methods("GET")
} }
func queryAuctionHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { func queryAuctionHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
@ -30,12 +30,12 @@ func queryAuctionHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
// Prepare params for querier // Prepare params for querier
vars := mux.Vars(r) vars := mux.Vars(r)
if len(vars[RestAuctionID]) == 0 { if len(vars[restAuctionID]) == 0 {
err := fmt.Errorf("%s required but not specified", RestAuctionID) err := fmt.Errorf("%s required but not specified", restAuctionID)
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return return
} }
auctionID, ok := rest.ParseUint64OrReturnBadRequest(w, vars[RestAuctionID]) auctionID, ok := rest.ParseUint64OrReturnBadRequest(w, vars[restAuctionID])
if !ok { if !ok {
return return
} }
@ -51,17 +51,17 @@ func queryAuctionHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return return
} }
// Decode and return results
cliCtx = cliCtx.WithHeight(height)
var auction types.Auction var auction types.Auction
err = cliCtx.Codec.UnmarshalJSON(res, &auction) err = cliCtx.Codec.UnmarshalJSON(res, &auction)
if err != nil { if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return return
} }
// Decode and return results
cliCtx = cliCtx.WithHeight(height)
auctionWithPhase := types.NewAuctionWithPhase(auction) auctionWithPhase := types.NewAuctionWithPhase(auction)
rest.PostProcessResponse(w, cliCtx, cliCtx.Codec.MustMarshalJSON(auctionWithPhase)) rest.PostProcessResponse(w, cliCtx, cliCtx.Codec.MustMarshalJSON(auctionWithPhase))
} }
} }
@ -73,13 +73,15 @@ func queryAuctionsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
if !ok { if !ok {
return return
} }
// Get all auctions // Get all auctions
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("/custom/%s/%s", types.ModuleName, types.QueryGetAuctions), nil) res, height, err := cliCtx.QueryWithData(fmt.Sprintf("/custom/%s/%s", types.ModuleName, types.QueryGetAuctions), nil)
if err != nil { if err != nil {
rest.WriteErrorResponse(w, http.StatusNotFound, err.Error()) rest.WriteErrorResponse(w, http.StatusNotFound, err.Error())
return return
} }
// Return auctions
// Decode and return results
cliCtx = cliCtx.WithHeight(height) cliCtx = cliCtx.WithHeight(height)
var auctions types.Auctions var auctions types.Auctions
@ -89,11 +91,10 @@ func queryAuctionsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return return
} }
var auctionsWithPhase []types.AuctionWithPhase auctionsWithPhase := []types.AuctionWithPhase{} // using empty slice so json returns [] instead of null when there's no auctions
for _, a := range auctions { for _, a := range auctions {
auctionsWithPhase = append(auctionsWithPhase, types.NewAuctionWithPhase(a)) auctionsWithPhase = append(auctionsWithPhase, types.NewAuctionWithPhase(a))
} }
rest.PostProcessResponse(w, cliCtx, cliCtx.Codec.MustMarshalJSON(auctionsWithPhase)) rest.PostProcessResponse(w, cliCtx, cliCtx.Codec.MustMarshalJSON(auctionsWithPhase))
} }
} }
@ -111,7 +112,7 @@ func getParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return return
} }
// Return the params // Decode and return results
cliCtx = cliCtx.WithHeight(height) cliCtx = cliCtx.WithHeight(height)
rest.PostProcessResponse(w, cliCtx, res) rest.PostProcessResponse(w, cliCtx, res)
} }

View File

@ -1,10 +1,8 @@
package rest package rest
import ( import (
"bytes"
"fmt" "fmt"
"net/http" "net/http"
"strconv"
"github.com/gorilla/mux" "github.com/gorilla/mux"
@ -16,65 +14,45 @@ import (
"github.com/kava-labs/kava/x/auction/types" "github.com/kava-labs/kava/x/auction/types"
) )
type placeBidReq struct { func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
BaseReq rest.BaseReq `json:"base_req"` r.HandleFunc(fmt.Sprintf("/{%s}/auctions/{%s}/bids", types.ModuleName, restAuctionID), bidHandlerFn(cliCtx)).Methods("POST")
AuctionID string `json:"auction_id"`
Bidder string `json:"bidder"`
Bid string `json:"bid"`
Lot string `json:"lot"`
} }
const ( type placeBidReq struct {
restAuctionID = "auction_id" BaseReq rest.BaseReq `json:"base_req"`
restBidder = "bidder" Amount sdk.Coin `json:"amount"`
restBid = "bid"
restLot = "lot"
)
func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc(
fmt.Sprintf("/auction/bid/{%s}/{%s}/{%s}", restAuctionID, restBidder, restBid), bidHandlerFn(cliCtx)).Methods("PUT")
} }
func bidHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { func bidHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// Get auction ID from url
auctionID, ok := rest.ParseUint64OrReturnBadRequest(w, mux.Vars(r)[restAuctionID])
if !ok {
return
}
// Get info from the http request body
var req placeBidReq var req placeBidReq
vars := mux.Vars(r) if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
strAuctionID := vars[restAuctionID] return
bechBidder := vars[restBidder] }
strBid := vars[restBid] req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
auctionID, err := strconv.ParseUint(strAuctionID, 10, 64) return
}
bidderAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil { if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return return
} }
bidder, err := sdk.AccAddressFromBech32(bechBidder) // Create and return a StdTx
if err != nil { msg := types.NewMsgPlaceBid(auctionID, bidderAddr, req.Amount)
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
bid, err := sdk.ParseCoin(strBid)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
msg := types.NewMsgPlaceBid(auctionID, bidder, bid)
if err := msg.ValidateBasic(); err != nil { if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return return
} }
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if !bytes.Equal(fromAddr, bidder) {
rest.WriteErrorResponse(w, http.StatusUnauthorized, "must bid from own address")
return
}
utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg}) utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
} }
} }

View File

@ -87,7 +87,7 @@ func TestDebtAuctionBasic(t *testing.T) {
tApp.CheckBalance(t, ctx, buyerAddr, cs(c("debt", 80))) tApp.CheckBalance(t, ctx, buyerAddr, cs(c("debt", 80)))
// Place a bid // Place a bid
require.NoError(t, keeper.PlaceBid(ctx, 0, seller, c("token2", 10))) require.NoError(t, keeper.PlaceBid(ctx, auctionID, seller, c("token2", 10)))
// Check seller's coins have decreased // Check seller's coins have decreased
tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 100))) tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 100)))
// Check buyer's coins have increased // Check buyer's coins have increased
@ -127,7 +127,7 @@ func TestDebtAuctionDebtRemaining(t *testing.T) {
tApp.CheckBalance(t, ctx, buyerAddr, cs(c("debt", 80))) tApp.CheckBalance(t, ctx, buyerAddr, cs(c("debt", 80)))
// Place a bid // Place a bid
require.NoError(t, keeper.PlaceBid(ctx, 0, seller, c("token2", 10))) require.NoError(t, keeper.PlaceBid(ctx, auctionID, seller, c("token2", 10)))
// Check seller's coins have decreased // Check seller's coins have decreased
tApp.CheckBalance(t, ctx, seller, cs(c("token1", 90), c("token2", 100))) tApp.CheckBalance(t, ctx, seller, cs(c("token1", 90), c("token2", 100)))
// Check buyer's coins have increased // Check buyer's coins have increased
@ -173,7 +173,7 @@ func TestCollateralAuctionBasic(t *testing.T) {
tApp.CheckBalance(t, ctx, sellerAddr, cs(c("token1", 80), c("token2", 100), c("debt", 60))) tApp.CheckBalance(t, ctx, sellerAddr, cs(c("token1", 80), c("token2", 100), c("debt", 60)))
// Place a forward bid // Place a forward bid
require.NoError(t, keeper.PlaceBid(ctx, 0, buyer, c("token2", 10))) require.NoError(t, keeper.PlaceBid(ctx, auctionID, buyer, c("token2", 10)))
// Check bidder's coins have decreased // Check bidder's coins have decreased
tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 90))) tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 90)))
// Check seller's coins have increased // Check seller's coins have increased
@ -184,8 +184,8 @@ func TestCollateralAuctionBasic(t *testing.T) {
} }
// Place a reverse bid // Place a reverse bid
require.NoError(t, keeper.PlaceBid(ctx, 0, buyer, c("token2", 50))) // first bid up to max bid to switch phases require.NoError(t, keeper.PlaceBid(ctx, auctionID, buyer, c("token2", 50))) // first bid up to max bid to switch phases
require.NoError(t, keeper.PlaceBid(ctx, 0, buyer, c("token1", 15))) require.NoError(t, keeper.PlaceBid(ctx, auctionID, buyer, c("token1", 15)))
// Check bidder's coins have decreased // Check bidder's coins have decreased
tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 50))) tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 50)))
// Check seller's coins have increased // Check seller's coins have increased
@ -233,7 +233,7 @@ func TestCollateralAuctionDebtRemaining(t *testing.T) {
tApp.CheckBalance(t, ctx, sellerAddr, cs(c("token1", 80), c("token2", 100), c("debt", 60))) tApp.CheckBalance(t, ctx, sellerAddr, cs(c("token1", 80), c("token2", 100), c("debt", 60)))
// Place a forward bid // Place a forward bid
require.NoError(t, keeper.PlaceBid(ctx, 0, buyer, c("token2", 10))) require.NoError(t, keeper.PlaceBid(ctx, auctionID, buyer, c("token2", 10)))
// Check bidder's coins have decreased // Check bidder's coins have decreased
tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 90))) tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 100), c("token2", 90)))
// Check seller's coins have increased // Check seller's coins have increased
@ -322,7 +322,7 @@ func TestStartSurplusAuction(t *testing.T) {
// check auction in store and is correct // check auction in store and is correct
require.True(t, found) require.True(t, found)
expectedAuction := types.Auction(types.SurplusAuction{BaseAuction: types.BaseAuction{ expectedAuction := types.Auction(types.SurplusAuction{BaseAuction: types.BaseAuction{
ID: 0, ID: id,
Initiator: tc.args.seller, Initiator: tc.args.seller,
Lot: tc.args.lot, Lot: tc.args.lot,
Bidder: nil, Bidder: nil,

View File

@ -78,7 +78,7 @@ func (suite *QuerierTestSuite) TestQueryAuction() {
// Set up request query // Set up request query
query := abci.RequestQuery{ query := abci.RequestQuery{
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetAuction}, "/"), Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetAuction}, "/"),
Data: types.ModuleCdc.MustMarshalJSON(types.QueryAuctionParams{AuctionID: 0}), // get the first auction Data: types.ModuleCdc.MustMarshalJSON(types.QueryAuctionParams{AuctionID: types.DefaultNextAuctionID}), // get the first auction
} }
// Execute query and check the []byte result // Execute query and check the []byte result

View File

@ -17,12 +17,15 @@ var DistantFuture = time.Date(9000, 1, 1, 0, 0, 0, 0, time.UTC)
type Auction interface { type Auction interface {
GetID() uint64 GetID() uint64
WithID(uint64) Auction WithID(uint64) Auction
GetInitiator() string GetInitiator() string
GetLot() sdk.Coin GetLot() sdk.Coin
GetBidder() sdk.AccAddress GetBidder() sdk.AccAddress
GetBid() sdk.Coin GetBid() sdk.Coin
GetEndTime() time.Time GetEndTime() time.Time
GetType() string GetType() string
GetPhase() string
} }
// Auctions is a slice of auctions. // Auctions is a slice of auctions.
@ -86,7 +89,7 @@ func (a BaseAuction) String() string {
// SurplusAuction is a forward auction that burns what it receives from bids. // SurplusAuction is a forward auction that burns what it receives from bids.
// It is normally used to sell off excess pegged asset acquired by the CDP system. // It is normally used to sell off excess pegged asset acquired by the CDP system.
type SurplusAuction struct { type SurplusAuction struct {
BaseAuction BaseAuction `json:"base_auction" yaml:"base_auction"`
} }
// WithID returns an auction with the ID set. // WithID returns an auction with the ID set.
@ -102,6 +105,9 @@ func (a SurplusAuction) GetModuleAccountCoins() sdk.Coins {
return sdk.NewCoins(a.Lot) return sdk.NewCoins(a.Lot)
} }
// GetPhase returns the direction of a surplus auction, which never changes.
func (a SurplusAuction) GetPhase() string { return "forward" }
// NewSurplusAuction returns a new surplus auction. // NewSurplusAuction returns a new surplus auction.
func NewSurplusAuction(seller string, lot sdk.Coin, bidDenom string, endTime time.Time) SurplusAuction { func NewSurplusAuction(seller string, lot sdk.Coin, bidDenom string, endTime time.Time) SurplusAuction {
auction := SurplusAuction{BaseAuction{ auction := SurplusAuction{BaseAuction{
@ -120,7 +126,7 @@ func NewSurplusAuction(seller string, lot sdk.Coin, bidDenom string, endTime tim
// DebtAuction is a reverse auction that mints what it pays out. // DebtAuction is a reverse auction that mints what it pays out.
// It is normally used to acquire pegged asset to cover the CDP system's debts that were not covered by selling collateral. // It is normally used to acquire pegged asset to cover the CDP system's debts that were not covered by selling collateral.
type DebtAuction struct { type DebtAuction struct {
BaseAuction BaseAuction `json:"base_auction" yaml:"base_auction"`
CorrespondingDebt sdk.Coin `json:"corresponding_debt" yaml:"corresponding_debt"` CorrespondingDebt sdk.Coin `json:"corresponding_debt" yaml:"corresponding_debt"`
} }
@ -139,6 +145,9 @@ func (a DebtAuction) GetModuleAccountCoins() sdk.Coins {
return sdk.NewCoins(a.CorrespondingDebt) return sdk.NewCoins(a.CorrespondingDebt)
} }
// GetPhase returns the direction of a debt auction, which never changes.
func (a DebtAuction) GetPhase() string { return "reverse" }
// NewDebtAuction returns a new debt auction. // NewDebtAuction returns a new debt auction.
func NewDebtAuction(buyerModAccName string, bid sdk.Coin, initialLot sdk.Coin, endTime time.Time, debt sdk.Coin) DebtAuction { func NewDebtAuction(buyerModAccName string, bid sdk.Coin, initialLot sdk.Coin, endTime time.Time, debt sdk.Coin) DebtAuction {
// Note: Bidder is set to the initiator's module account address instead of module name. (when the first bid is placed, it is paid out to the initiator) // Note: Bidder is set to the initiator's module account address instead of module name. (when the first bid is placed, it is paid out to the initiator)
@ -165,7 +174,7 @@ func NewDebtAuction(buyerModAccName string, bid sdk.Coin, initialLot sdk.Coin, e
// Unsold Lot is sent to LotReturns, being divided among the addresses by weight. // Unsold Lot is sent to LotReturns, being divided among the addresses by weight.
// Collateral auctions are normally used to sell off collateral seized from CDPs. // Collateral auctions are normally used to sell off collateral seized from CDPs.
type CollateralAuction struct { type CollateralAuction struct {
BaseAuction BaseAuction `json:"base_auction" yaml:"base_auction"`
CorrespondingDebt sdk.Coin `json:"corresponding_debt" yaml:"corresponding_debt"` CorrespondingDebt sdk.Coin `json:"corresponding_debt" yaml:"corresponding_debt"`
MaxBid sdk.Coin `json:"max_bid" yaml:"max_bid"` MaxBid sdk.Coin `json:"max_bid" yaml:"max_bid"`
@ -186,12 +195,12 @@ func (a CollateralAuction) GetModuleAccountCoins() sdk.Coins {
} }
// IsReversePhase returns whether the auction has switched over to reverse phase or not. // IsReversePhase returns whether the auction has switched over to reverse phase or not.
// Auction initially start in forward phase. // CollateralAuctions initially start in forward phase.
func (a CollateralAuction) IsReversePhase() bool { func (a CollateralAuction) IsReversePhase() bool {
return a.Bid.IsEqual(a.MaxBid) return a.Bid.IsEqual(a.MaxBid)
} }
// GetPhase returns the phase of a collateral auction // GetPhase returns the direction of a collateral auction.
func (a CollateralAuction) GetPhase() string { func (a CollateralAuction) GetPhase() string {
if a.IsReversePhase() { if a.IsReversePhase() {
return "reverse" return "reverse"

View File

@ -7,6 +7,9 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
) )
// DefaultNextAuctionID is the starting poiint for auction IDs.
const DefaultNextAuctionID uint64 = 1
// GenesisAuction is an interface that extends the auction interface to add functionality needed for initializing auctions from genesis. // GenesisAuction is an interface that extends the auction interface to add functionality needed for initializing auctions from genesis.
type GenesisAuction interface { type GenesisAuction interface {
Auction Auction
@ -35,7 +38,11 @@ func NewGenesisState(nextID uint64, ap Params, ga GenesisAuctions) GenesisState
// DefaultGenesisState returns the default genesis state for auction module. // DefaultGenesisState returns the default genesis state for auction module.
func DefaultGenesisState() GenesisState { func DefaultGenesisState() GenesisState {
return NewGenesisState(0, DefaultParams(), GenesisAuctions{}) return NewGenesisState(
DefaultNextAuctionID,
DefaultParams(),
GenesisAuctions{},
)
} }
// Equal checks whether two GenesisState structs are equivalent. // Equal checks whether two GenesisState structs are equivalent.

View File

@ -1,6 +1,9 @@
package types package types
import sdk "github.com/cosmos/cosmos-sdk/types" import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// ensure Msg interface compliance at compile time // ensure Msg interface compliance at compile time
var _ sdk.Msg = &MsgPlaceBid{} var _ sdk.Msg = &MsgPlaceBid{}
@ -30,10 +33,10 @@ func (msg MsgPlaceBid) Type() string { return "place_bid" }
// ValidateBasic does a simple validation check that doesn't require access to state. // ValidateBasic does a simple validation check that doesn't require access to state.
func (msg MsgPlaceBid) ValidateBasic() sdk.Error { func (msg MsgPlaceBid) ValidateBasic() sdk.Error {
if msg.Bidder.Empty() { if msg.Bidder.Empty() {
return sdk.ErrInternal("invalid (empty) bidder address") return sdk.ErrInvalidAddress("invalid (empty) bidder address")
} }
if !msg.Amount.IsValid() { if !msg.Amount.IsValid() {
return sdk.ErrInvalidCoins(msg.Amount.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("invalid bid amount: %s", msg.Amount))
} }
return nil return nil
} }

View File

@ -30,7 +30,7 @@ func NewQueryAllAuctionParams(page int, limit int) QueryAllAuctionParams {
// AuctionWithPhase augmented type for collateral auctions which includes auction phase for querying // AuctionWithPhase augmented type for collateral auctions which includes auction phase for querying
type AuctionWithPhase struct { type AuctionWithPhase struct {
Auction Auction Auction Auction `json:"auction" yaml:"auction"`
Type string `json:"type" yaml:"type"` Type string `json:"type" yaml:"type"`
Phase string `json:"phase" yaml:"phase"` Phase string `json:"phase" yaml:"phase"`
@ -38,17 +38,9 @@ type AuctionWithPhase struct {
// NewAuctionWithPhase returns new AuctionWithPhase // NewAuctionWithPhase returns new AuctionWithPhase
func NewAuctionWithPhase(a Auction) AuctionWithPhase { func NewAuctionWithPhase(a Auction) AuctionWithPhase {
switch auc := a.(type) {
case CollateralAuction:
return AuctionWithPhase{ return AuctionWithPhase{
Auction: auc, Auction: a,
Type: auc.GetType(), Type: a.GetType(),
Phase: auc.GetPhase(), Phase: a.GetPhase(),
}
default:
return AuctionWithPhase{
Auction: auc,
Type: auc.GetType(),
}
} }
} }

View File

@ -7,13 +7,14 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
tmtime "github.com/tendermint/tendermint/types/time"
"github.com/kava-labs/kava/app" "github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/auction" "github.com/kava-labs/kava/x/auction"
"github.com/kava-labs/kava/x/cdp/keeper" "github.com/kava-labs/kava/x/cdp/keeper"
"github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/cdp/types"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
tmtime "github.com/tendermint/tendermint/types/time"
) )
type SeizeTestSuite struct { type SeizeTestSuite struct {
@ -136,7 +137,7 @@ func (suite *SeizeTestSuite) TestSeizeCollateral() {
tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx") tpa := suite.keeper.GetTotalPrincipal(suite.ctx, "xrp", "usdx")
suite.Equal(tpb.Sub(tpa), p) suite.Equal(tpb.Sub(tpa), p)
auctionKeeper := suite.app.GetAuctionKeeper() auctionKeeper := suite.app.GetAuctionKeeper()
_, found := auctionKeeper.GetAuction(suite.ctx, 0) _, found := auctionKeeper.GetAuction(suite.ctx, auction.DefaultNextAuctionID)
suite.True(found) suite.True(found)
auctionMacc := sk.GetModuleAccount(suite.ctx, auction.ModuleName) auctionMacc := sk.GetModuleAccount(suite.ctx, auction.ModuleName)
suite.Equal(cs(c("debt", p.Int64()), c("xrp", cl.Int64())), auctionMacc.GetCoins()) suite.Equal(cs(c("debt", p.Int64()), c("xrp", cl.Int64())), auctionMacc.GetCoins())

View File

@ -46,16 +46,16 @@ func (msg MsgCreateCDP) ValidateBasic() sdk.Error {
return sdk.ErrInvalidCoins(fmt.Sprintf("cdps do not support multiple collateral types: received %s", msg.Collateral)) return sdk.ErrInvalidCoins(fmt.Sprintf("cdps do not support multiple collateral types: received %s", msg.Collateral))
} }
if !msg.Collateral.IsValid() { if !msg.Collateral.IsValid() {
return sdk.ErrInvalidCoins(msg.Collateral.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("invalid collateral amount: %s", msg.Collateral))
} }
if !msg.Collateral.IsAllPositive() { if !msg.Collateral.IsAllPositive() {
return sdk.ErrInvalidCoins(msg.Collateral.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("negative collateral amount: %s", msg.Collateral))
} }
if !msg.Principal.IsValid() { if !msg.Principal.IsValid() {
return sdk.ErrInvalidCoins(msg.Principal.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("invalid principal amount: %s", msg.Principal))
} }
if !msg.Principal.IsAllPositive() { if !msg.Principal.IsAllPositive() {
return sdk.ErrInvalidCoins(msg.Collateral.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("negative principal amount: %s", msg.Principal))
} }
return nil return nil
} }
@ -114,10 +114,10 @@ func (msg MsgDeposit) ValidateBasic() sdk.Error {
return sdk.ErrInvalidCoins(fmt.Sprintf("cdps do not support multiple collateral types: received %s", msg.Collateral)) return sdk.ErrInvalidCoins(fmt.Sprintf("cdps do not support multiple collateral types: received %s", msg.Collateral))
} }
if !msg.Collateral.IsValid() { if !msg.Collateral.IsValid() {
return sdk.ErrInvalidCoins(msg.Collateral.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("invalid collateral amount: %s", msg.Collateral))
} }
if !msg.Collateral.IsAllPositive() { if !msg.Collateral.IsAllPositive() {
return sdk.ErrInvalidCoins(msg.Collateral.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("negative collateral amount: %s", msg.Collateral))
} }
return nil return nil
} }
@ -176,10 +176,10 @@ func (msg MsgWithdraw) ValidateBasic() sdk.Error {
return sdk.ErrInvalidCoins(fmt.Sprintf("cdps do not support multiple collateral types: received %s", msg.Collateral)) return sdk.ErrInvalidCoins(fmt.Sprintf("cdps do not support multiple collateral types: received %s", msg.Collateral))
} }
if !msg.Collateral.IsValid() { if !msg.Collateral.IsValid() {
return sdk.ErrInvalidCoins(msg.Collateral.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("invalid collateral amount: %s", msg.Collateral))
} }
if !msg.Collateral.IsAllPositive() { if !msg.Collateral.IsAllPositive() {
return sdk.ErrInvalidCoins(msg.Collateral.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("negative collateral amount: %s", msg.Collateral))
} }
return nil return nil
} }
@ -235,10 +235,10 @@ func (msg MsgDrawDebt) ValidateBasic() sdk.Error {
return sdk.ErrInternal("invalid (empty) cdp denom") return sdk.ErrInternal("invalid (empty) cdp denom")
} }
if !msg.Principal.IsValid() { if !msg.Principal.IsValid() {
return sdk.ErrInvalidCoins(msg.Principal.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("invalid principal amount: %s", msg.Principal))
} }
if !msg.Principal.IsAllPositive() { if !msg.Principal.IsAllPositive() {
return sdk.ErrInvalidCoins(msg.Principal.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("negative principal amount: %s", msg.Principal))
} }
return nil return nil
} }
@ -294,10 +294,10 @@ func (msg MsgRepayDebt) ValidateBasic() sdk.Error {
return sdk.ErrInternal("invalid (empty) cdp denom") return sdk.ErrInternal("invalid (empty) cdp denom")
} }
if !msg.Payment.IsValid() { if !msg.Payment.IsValid() {
return sdk.ErrInvalidCoins(msg.Payment.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("invalid payment amount: %s", msg.Payment))
} }
if !msg.Payment.IsAllPositive() { if !msg.Payment.IsAllPositive() {
return sdk.ErrInvalidCoins(msg.Payment.String()) return sdk.ErrInvalidCoins(fmt.Sprintf("negative payment amount: %s", msg.Payment))
} }
return nil return nil
} }