Add changes from code review

This commit is contained in:
Jack Zampolin 2020-05-04 10:52:36 -07:00
parent 471565e360
commit f86d0f3c3b
6 changed files with 60 additions and 24 deletions

View File

@ -20,6 +20,7 @@ func (k Keeper) StartSurplusAuction(ctx sdk.Context, seller string, lot sdk.Coin
types.DistantFuture, types.DistantFuture,
) )
// NOTE: for the duration of the auction the auction module account holds the lot
err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot)) err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot))
if err != nil { if err != nil {
return 0, err return 0, err
@ -36,7 +37,7 @@ func (k Keeper) StartSurplusAuction(ctx sdk.Context, seller string, lot sdk.Coin
sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", auction.GetID())), sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", auction.GetID())),
sdk.NewAttribute(types.AttributeKeyAuctionType, auction.GetType()), sdk.NewAttribute(types.AttributeKeyAuctionType, auction.GetType()),
sdk.NewAttribute(types.AttributeKeyBidDenom, auction.Bid.Denom), sdk.NewAttribute(types.AttributeKeyBidDenom, auction.Bid.Denom),
sdk.NewAttribute(types.AttributeKeyLotDenom, auction.Lot.Denom), sdk.NewAttribute(types.AttributeKeyLot, auction.Lot.String()),
), ),
) )
return auctionID, nil return auctionID, nil
@ -50,14 +51,17 @@ func (k Keeper) StartDebtAuction(ctx sdk.Context, buyer string, bid sdk.Coin, in
bid, bid,
initialLot, initialLot,
types.DistantFuture, types.DistantFuture,
debt) debt,
)
// This auction type mints coins at close. Need to check module account has minting privileges to avoid potential err in endblocker. // This auction type mints coins at close. Need to check module account has minting privileges to avoid potential err in endblocker.
macc := k.supplyKeeper.GetModuleAccount(ctx, buyer) macc := k.supplyKeeper.GetModuleAccount(ctx, buyer)
if !macc.HasPermission(supply.Minter) { if !macc.HasPermission(supply.Minter) {
// TODO: this should panic?
return 0, sdkerrors.Wrap(types.ErrInvalidModulePermissions, supply.Minter) return 0, sdkerrors.Wrap(types.ErrInvalidModulePermissions, supply.Minter)
} }
// NOTE: for the duration of the auction the auction module account holds the debt
err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, buyer, types.ModuleName, sdk.NewCoins(debt)) err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, buyer, types.ModuleName, sdk.NewCoins(debt))
if err != nil { if err != nil {
return 0, err return 0, err
@ -74,7 +78,7 @@ func (k Keeper) StartDebtAuction(ctx sdk.Context, buyer string, bid sdk.Coin, in
sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", auction.GetID())), sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", auction.GetID())),
sdk.NewAttribute(types.AttributeKeyAuctionType, auction.GetType()), sdk.NewAttribute(types.AttributeKeyAuctionType, auction.GetType()),
sdk.NewAttribute(types.AttributeKeyBidDenom, auction.Bid.Denom), sdk.NewAttribute(types.AttributeKeyBidDenom, auction.Bid.Denom),
sdk.NewAttribute(types.AttributeKeyLotDenom, auction.Lot.Denom), sdk.NewAttribute(types.AttributeKeyLot, auction.Lot.String()),
), ),
) )
return auctionID, nil return auctionID, nil
@ -98,6 +102,7 @@ func (k Keeper) StartCollateralAuction(
debt, debt,
) )
// NOTE: for the duration of the auction the auction module account holds the debt and the lot
err = k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot)) err = k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot))
if err != nil { if err != nil {
return 0, err return 0, err
@ -118,7 +123,8 @@ func (k Keeper) StartCollateralAuction(
sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", auction.GetID())), sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", auction.GetID())),
sdk.NewAttribute(types.AttributeKeyAuctionType, auction.GetType()), sdk.NewAttribute(types.AttributeKeyAuctionType, auction.GetType()),
sdk.NewAttribute(types.AttributeKeyBidDenom, auction.Bid.Denom), sdk.NewAttribute(types.AttributeKeyBidDenom, auction.Bid.Denom),
sdk.NewAttribute(types.AttributeKeyLotDenom, auction.Lot.Denom), sdk.NewAttribute(types.AttributeKeyLot, auction.Lot.String()),
sdk.NewAttribute(types.AttributeKeyMaxBidAmount, auction.MaxBid.String()),
), ),
) )
return auctionID, nil return auctionID, nil
@ -218,7 +224,7 @@ func (k Keeper) PlaceBidSurplus(ctx sdk.Context, a types.SurplusAuction, bidder
types.EventTypeAuctionBid, types.EventTypeAuctionBid,
sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", a.ID)), sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", a.ID)),
sdk.NewAttribute(types.AttributeKeyBidder, a.Bidder.String()), sdk.NewAttribute(types.AttributeKeyBidder, a.Bidder.String()),
sdk.NewAttribute(types.AttributeKeyBidAmount, a.Bid.Amount.String()), sdk.NewAttribute(types.AttributeKeyBid, a.Bid.String()),
sdk.NewAttribute(types.AttributeKeyEndTime, fmt.Sprintf("%d", a.EndTime.Unix())), sdk.NewAttribute(types.AttributeKeyEndTime, fmt.Sprintf("%d", a.EndTime.Unix())),
), ),
) )
@ -233,6 +239,7 @@ func (k Keeper) PlaceForwardBidCollateral(ctx sdk.Context, a types.CollateralAuc
return a, sdkerrors.Wrapf(types.ErrInvalidBidDenom, "%s ≠ %s", bid.Denom, a.Bid.Denom) return a, sdkerrors.Wrapf(types.ErrInvalidBidDenom, "%s ≠ %s", bid.Denom, a.Bid.Denom)
} }
if a.IsReversePhase() { if a.IsReversePhase() {
// TODO: panic maybe?
return a, sdkerrors.Wrapf(types.ErrCollateralAuctionIsInReversePhase, "%d", a.ID) return a, sdkerrors.Wrapf(types.ErrCollateralAuctionIsInReversePhase, "%d", a.ID)
} }
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 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
@ -294,7 +301,7 @@ func (k Keeper) PlaceForwardBidCollateral(ctx sdk.Context, a types.CollateralAuc
types.EventTypeAuctionBid, types.EventTypeAuctionBid,
sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", a.ID)), sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", a.ID)),
sdk.NewAttribute(types.AttributeKeyBidder, a.Bidder.String()), sdk.NewAttribute(types.AttributeKeyBidder, a.Bidder.String()),
sdk.NewAttribute(types.AttributeKeyBidAmount, a.Bid.Amount.String()), sdk.NewAttribute(types.AttributeKeyBid, a.Bid.String()),
sdk.NewAttribute(types.AttributeKeyEndTime, fmt.Sprintf("%d", a.EndTime.Unix())), sdk.NewAttribute(types.AttributeKeyEndTime, fmt.Sprintf("%d", a.EndTime.Unix())),
), ),
) )
@ -309,6 +316,7 @@ func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuc
return a, sdkerrors.Wrapf(types.ErrInvalidLotDenom, lot.Denom, a.Lot.Denom) return a, sdkerrors.Wrapf(types.ErrInvalidLotDenom, lot.Denom, a.Lot.Denom)
} }
if !a.IsReversePhase() { if !a.IsReversePhase() {
// TODO: Panic here?
return a, sdkerrors.Wrapf(types.ErrCollateralAuctionIsInForwardPhase, "%d", a.ID) return a, sdkerrors.Wrapf(types.ErrCollateralAuctionIsInForwardPhase, "%d", a.ID)
} }
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 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
@ -336,16 +344,20 @@ func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuc
return a, err return a, err
} }
} }
// Decrease in lot is sent to weighted addresses (normally the CDP depositors) // Decrease in lot is sent to weighted addresses (normally the CDP depositors)
// TODO paying out rateably to cdp depositors is vulnerable to errors compounding over multiple bids - check this can't be gamed. // TODO: paying out rateably to cdp depositors is vulnerable to errors compounding over multiple bids - check this can't be gamed.
lotPayouts, err := splitCoinIntoWeightedBuckets(a.Lot.Sub(lot), a.LotReturns.Weights) lotPayouts, err := splitCoinIntoWeightedBuckets(a.Lot.Sub(lot), a.LotReturns.Weights)
if err != nil { if err != nil {
return a, err return a, err
} }
for i, payout := range lotPayouts { for i, payout := range lotPayouts {
err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.LotReturns.Addresses[i], sdk.NewCoins(payout)) // if due to rounding, for whatever reason, the lot amount is 0, don't execute the following code
if err != nil { if payout.IsPositive() {
return a, err err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.LotReturns.Addresses[i], sdk.NewCoins(payout))
if err != nil {
return a, err
}
} }
} }
@ -363,7 +375,7 @@ func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuc
types.EventTypeAuctionBid, types.EventTypeAuctionBid,
sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", a.ID)), sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", a.ID)),
sdk.NewAttribute(types.AttributeKeyBidder, a.Bidder.String()), sdk.NewAttribute(types.AttributeKeyBidder, a.Bidder.String()),
sdk.NewAttribute(types.AttributeKeyLotAmount, a.Lot.Amount.String()), sdk.NewAttribute(types.AttributeKeyLot, a.Lot.String()),
sdk.NewAttribute(types.AttributeKeyEndTime, fmt.Sprintf("%d", a.EndTime.Unix())), sdk.NewAttribute(types.AttributeKeyEndTime, fmt.Sprintf("%d", a.EndTime.Unix())),
), ),
) )
@ -429,7 +441,7 @@ func (k Keeper) PlaceBidDebt(ctx sdk.Context, a types.DebtAuction, bidder sdk.Ac
types.EventTypeAuctionBid, types.EventTypeAuctionBid,
sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", a.ID)), sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", a.ID)),
sdk.NewAttribute(types.AttributeKeyBidder, a.Bidder.String()), sdk.NewAttribute(types.AttributeKeyBidder, a.Bidder.String()),
sdk.NewAttribute(types.AttributeKeyLotAmount, a.Lot.Amount.String()), sdk.NewAttribute(types.AttributeKeyLot, a.Lot.String()),
sdk.NewAttribute(types.AttributeKeyEndTime, fmt.Sprintf("%d", a.EndTime.Unix())), sdk.NewAttribute(types.AttributeKeyEndTime, fmt.Sprintf("%d", a.EndTime.Unix())),
), ),
) )
@ -442,10 +454,13 @@ func (k Keeper) CloseAuction(ctx sdk.Context, auctionID uint64) error {
auction, found := k.GetAuction(ctx, auctionID) auction, found := k.GetAuction(ctx, auctionID)
if !found { if !found {
// TODO: panic if we are closing an auction in BB that isn't in the store?
// how else would we get here?
return sdkerrors.Wrapf(types.ErrAuctionNotFound, "%d", auctionID) return sdkerrors.Wrapf(types.ErrAuctionNotFound, "%d", auctionID)
} }
if ctx.BlockTime().Before(auction.GetEndTime()) { if ctx.BlockTime().Before(auction.GetEndTime()) {
// TODO: Do we check this upstream? should this be a panic
return sdkerrors.Wrapf(types.ErrAuctionHasNotExpired, "block time %s, auction end time %s", ctx.BlockTime().UTC(), auction.GetEndTime().UTC()) return sdkerrors.Wrapf(types.ErrAuctionHasNotExpired, "block time %s, auction end time %s", ctx.BlockTime().UTC(), auction.GetEndTime().UTC())
} }
@ -473,6 +488,7 @@ func (k Keeper) CloseAuction(ctx sdk.Context, auctionID uint64) error {
sdk.NewEvent( sdk.NewEvent(
types.EventTypeAuctionClose, types.EventTypeAuctionClose,
sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", auction.GetID())), sdk.NewAttribute(types.AttributeKeyAuctionID, fmt.Sprintf("%d", auction.GetID())),
// TODO: add closed height here to facilitate the query of the auction after it closes
), ),
) )
return nil return nil
@ -480,17 +496,23 @@ func (k Keeper) CloseAuction(ctx sdk.Context, auctionID uint64) error {
// PayoutDebtAuction pays out the proceeds for a debt auction, first minting the coins. // PayoutDebtAuction pays out the proceeds for a debt auction, first minting the coins.
func (k Keeper) PayoutDebtAuction(ctx sdk.Context, a types.DebtAuction) error { func (k Keeper) PayoutDebtAuction(ctx sdk.Context, a types.DebtAuction) error {
// create the coins that are needed to pay off the debt
err := k.supplyKeeper.MintCoins(ctx, a.Initiator, sdk.NewCoins(a.Lot)) err := k.supplyKeeper.MintCoins(ctx, a.Initiator, sdk.NewCoins(a.Lot))
if err != nil { if err != nil {
// TODO: how would we get here? should this be a panic?
return err return err
} }
// send the new coins from the initiator module to the bidder
err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, a.Initiator, a.Bidder, sdk.NewCoins(a.Lot)) err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, a.Initiator, a.Bidder, sdk.NewCoins(a.Lot))
if err != nil { if err != nil {
// TODO: how would we get here? should this be a panic?
return err return err
} }
// if there is remaining debt, return it to the calling module to manage
if a.CorrespondingDebt.IsPositive() { if a.CorrespondingDebt.IsPositive() {
err = k.supplyKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, a.Initiator, sdk.NewCoins(a.CorrespondingDebt)) err = k.supplyKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, a.Initiator, sdk.NewCoins(a.CorrespondingDebt))
if err != nil { if err != nil {
// TODO: how would we get here? should this be a panic?
return err return err
} }
} }
@ -499,8 +521,10 @@ func (k Keeper) PayoutDebtAuction(ctx sdk.Context, a types.DebtAuction) error {
// PayoutSurplusAuction pays out the proceeds for a surplus auction. // PayoutSurplusAuction pays out the proceeds for a surplus auction.
func (k Keeper) PayoutSurplusAuction(ctx sdk.Context, a types.SurplusAuction) error { func (k Keeper) PayoutSurplusAuction(ctx sdk.Context, a types.SurplusAuction) error {
// Send the tokens from the auction module account where they are being managed to the bidder who won the auction
err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.Bidder, sdk.NewCoins(a.Lot)) err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.Bidder, sdk.NewCoins(a.Lot))
if err != nil { if err != nil {
// TODO: how would we get here? should this be a panic?
return err return err
} }
return nil return nil
@ -508,13 +532,18 @@ func (k Keeper) PayoutSurplusAuction(ctx sdk.Context, a types.SurplusAuction) er
// PayoutCollateralAuction pays out the proceeds for a collateral auction. // PayoutCollateralAuction pays out the proceeds for a collateral auction.
func (k Keeper) PayoutCollateralAuction(ctx sdk.Context, a types.CollateralAuction) error { func (k Keeper) PayoutCollateralAuction(ctx sdk.Context, a types.CollateralAuction) error {
// Send the tokens from the auction module account where they are being managed to the bidder who won the auction
err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.Bidder, sdk.NewCoins(a.Lot)) err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.Bidder, sdk.NewCoins(a.Lot))
if err != nil { if err != nil {
// TODO: how would we get here? should this be a panic?
return err return err
} }
// if there is remaining debt after the auction, send it back to the initiating module for management
if a.CorrespondingDebt.IsPositive() { if a.CorrespondingDebt.IsPositive() {
err = k.supplyKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, a.Initiator, sdk.NewCoins(a.CorrespondingDebt)) err = k.supplyKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, a.Initiator, sdk.NewCoins(a.CorrespondingDebt))
if err != nil { if err != nil {
// TODO: how would we get here? should this be a panic?
return err return err
} }
} }
@ -549,6 +578,7 @@ func earliestTime(t1, t2 time.Time) time.Time {
func splitCoinIntoWeightedBuckets(coin sdk.Coin, buckets []sdk.Int) ([]sdk.Coin, error) { func splitCoinIntoWeightedBuckets(coin sdk.Coin, buckets []sdk.Int) ([]sdk.Coin, error) {
for _, bucket := range buckets { for _, bucket := range buckets {
if bucket.IsNegative() { if bucket.IsNegative() {
// TODO: Panic here? How would the code get here (should catch at validation)
return nil, fmt.Errorf("cannot split %s into bucket with negative weight (%s)", coin.String(), bucket.String()) return nil, fmt.Errorf("cannot split %s into bucket with negative weight (%s)", coin.String(), bucket.String())
} }
} }

View File

@ -74,6 +74,7 @@ func (k Keeper) IncrementNextAuctionID(ctx sdk.Context) error {
func (k Keeper) StoreNewAuction(ctx sdk.Context, auction types.Auction) (uint64, error) { func (k Keeper) StoreNewAuction(ctx sdk.Context, auction types.Auction) (uint64, error) {
newAuctionID, err := k.GetNextAuctionID(ctx) newAuctionID, err := k.GetNextAuctionID(ctx)
if err != nil { if err != nil {
// TODO: We might want to panic on this condition
return 0, err return 0, err
} }
auction = auction.WithID(newAuctionID) auction = auction.WithID(newAuctionID)

View File

@ -11,7 +11,8 @@ import (
// https://en.wikipedia.org/wiki/Largest_remainder_method // https://en.wikipedia.org/wiki/Largest_remainder_method
// see also: https://stackoverflow.com/questions/13483430/how-to-make-rounded-percentages-add-up-to-100 // see also: https://stackoverflow.com/questions/13483430/how-to-make-rounded-percentages-add-up-to-100
func splitIntIntoWeightedBuckets(amount sdk.Int, buckets []sdk.Int) []sdk.Int { func splitIntIntoWeightedBuckets(amount sdk.Int, buckets []sdk.Int) []sdk.Int {
// TODO ideally change algorithm to work with -ve numbers. Limiting to +ve numbers until them // TODO: ideally change algorithm to work with -ve numbers. Limiting to +ve numbers until them
// TODO: negative buckets don't make sense in this context
if amount.IsNegative() { if amount.IsNegative() {
panic("negative amount") panic("negative amount")
} }

View File

@ -6,13 +6,16 @@ const (
EventTypeAuctionBid = "auction_bid" EventTypeAuctionBid = "auction_bid"
EventTypeAuctionClose = "auction_close" EventTypeAuctionClose = "auction_close"
AttributeValueCategory = ModuleName AttributeValueCategory = ModuleName
AttributeKeyAuctionID = "auction_id" AttributeKeyAuctionID = "auction_id"
AttributeKeyAuctionType = "auction_type" AttributeKeyAuctionType = "auction_type"
AttributeKeyBidder = "bidder" AttributeKeyBidder = "bidder"
AttributeKeyBidDenom = "bid_denom" AttributeKeyBidDenom = "bid_denom"
AttributeKeyLotDenom = "lot_denom" AttributeKeyLotDenom = "lot_denom"
AttributeKeyBidAmount = "bid_amount" AttributeKeyLot = "lot"
AttributeKeyLotAmount = "lot_amount" AttributeKeyMaxBidAmount = "max_bid"
AttributeKeyEndTime = "end_time" AttributeKeyBidAmount = "bid_amount"
AttributeKeyBid = "bid"
AttributeKeyLotAmount = "lot_amount"
AttributeKeyEndTime = "end_time"
) )

View File

@ -25,6 +25,7 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k Keeper) {
err := k.UpdateFeesForAllCdps(ctx, cp.Denom) err := k.UpdateFeesForAllCdps(ctx, cp.Denom)
// handle if an error is returned then propagate up // handle if an error is returned then propagate up
// TODO: panic here probably for mainnet (optional: have a bool that says panic or no)
if err != nil { if err != nil {
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
sdk.NewEvent( sdk.NewEvent(

View File

@ -13,8 +13,8 @@ import (
// 1. updates the fees for the input cdp, // 1. updates the fees for the input cdp,
// 2. sends collateral for all deposits from the cdp module to the liquidator module account // 2. sends collateral for all deposits from the cdp module to the liquidator module account
// 3. Applies the liquidation penalty and mints the corresponding amount of debt coins in the cdp module // 3. Applies the liquidation penalty and mints the corresponding amount of debt coins in the cdp module
// 3. moves debt coins from the cdp module to the liquidator module account, // 4. moves debt coins from the cdp module to the liquidator module account,
// 4. decrements the total amount of principal outstanding for that collateral type // 5. decrements the total amount of principal outstanding for that collateral type
// (this is the equivalent of saying that fees are no longer accumulated by a cdp once it gets liquidated) // (this is the equivalent of saying that fees are no longer accumulated by a cdp once it gets liquidated)
func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) error { func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) error {
// Calculate the previous collateral ratio // Calculate the previous collateral ratio