mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-26 08:15:19 +00:00
commit
6dedc1520a
@ -1,109 +1,105 @@
|
|||||||
package auction
|
package auction
|
||||||
|
|
||||||
|
// DO NOT EDIT - generated by aliasgen tool (github.com/rhuairahrighairidh/aliasgen)
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kava-labs/kava/x/auction/keeper"
|
"github.com/kava-labs/kava/x/auction/keeper"
|
||||||
"github.com/kava-labs/kava/x/auction/types"
|
"github.com/kava-labs/kava/x/auction/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// nolint
|
|
||||||
// autogenerated code using github.com/rigelrozanski/multitool
|
|
||||||
// aliases generated for the following subdirectories:
|
|
||||||
// ALIASGEN: github.com/kava-labs/kava/x/auction/keeper
|
|
||||||
// ALIASGEN: github.com/kava-labs/kava/x/auction/types
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EventTypeAuctionStart = types.EventTypeAuctionStart
|
|
||||||
EventTypeAuctionBid = types.EventTypeAuctionBid
|
|
||||||
EventTypeAuctionClose = types.EventTypeAuctionClose
|
|
||||||
AttributeValueCategory = types.AttributeValueCategory
|
|
||||||
AttributeKeyAuctionID = types.AttributeKeyAuctionID
|
AttributeKeyAuctionID = types.AttributeKeyAuctionID
|
||||||
AttributeKeyAuctionType = types.AttributeKeyAuctionType
|
AttributeKeyAuctionType = types.AttributeKeyAuctionType
|
||||||
|
AttributeKeyBid = types.AttributeKeyBid
|
||||||
AttributeKeyBidder = types.AttributeKeyBidder
|
AttributeKeyBidder = types.AttributeKeyBidder
|
||||||
AttributeKeyBidDenom = types.AttributeKeyBidDenom
|
AttributeKeyCloseBlock = types.AttributeKeyCloseBlock
|
||||||
AttributeKeyLotDenom = types.AttributeKeyLotDenom
|
|
||||||
AttributeKeyBidAmount = types.AttributeKeyBidAmount
|
|
||||||
AttributeKeyLotAmount = types.AttributeKeyLotAmount
|
|
||||||
AttributeKeyEndTime = types.AttributeKeyEndTime
|
AttributeKeyEndTime = types.AttributeKeyEndTime
|
||||||
DefaultNextAuctionID = types.DefaultNextAuctionID
|
AttributeKeyLot = types.AttributeKeyLot
|
||||||
ModuleName = types.ModuleName
|
AttributeKeyMaxBid = types.AttributeKeyMaxBid
|
||||||
StoreKey = types.StoreKey
|
AttributeValueCategory = types.AttributeValueCategory
|
||||||
RouterKey = types.RouterKey
|
|
||||||
DefaultParamspace = types.DefaultParamspace
|
|
||||||
QuerierRoute = types.QuerierRoute
|
|
||||||
DefaultMaxAuctionDuration = types.DefaultMaxAuctionDuration
|
|
||||||
DefaultBidDuration = types.DefaultBidDuration
|
DefaultBidDuration = types.DefaultBidDuration
|
||||||
|
DefaultMaxAuctionDuration = types.DefaultMaxAuctionDuration
|
||||||
|
DefaultNextAuctionID = types.DefaultNextAuctionID
|
||||||
|
DefaultParamspace = types.DefaultParamspace
|
||||||
|
EventTypeAuctionBid = types.EventTypeAuctionBid
|
||||||
|
EventTypeAuctionClose = types.EventTypeAuctionClose
|
||||||
|
EventTypeAuctionStart = types.EventTypeAuctionStart
|
||||||
|
ModuleName = types.ModuleName
|
||||||
|
QuerierRoute = types.QuerierRoute
|
||||||
QueryGetAuction = types.QueryGetAuction
|
QueryGetAuction = types.QueryGetAuction
|
||||||
QueryGetAuctions = types.QueryGetAuctions
|
QueryGetAuctions = types.QueryGetAuctions
|
||||||
QueryGetParams = types.QueryGetParams
|
QueryGetParams = types.QueryGetParams
|
||||||
|
RouterKey = types.RouterKey
|
||||||
|
StoreKey = types.StoreKey
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// functions aliases
|
// function aliases
|
||||||
NewKeeper = keeper.NewKeeper
|
ModuleAccountInvariants = keeper.ModuleAccountInvariants
|
||||||
NewQuerier = keeper.NewQuerier
|
NewKeeper = keeper.NewKeeper
|
||||||
RegisterInvariants = keeper.RegisterInvariants
|
NewQuerier = keeper.NewQuerier
|
||||||
NewSurplusAuction = types.NewSurplusAuction
|
RegisterInvariants = keeper.RegisterInvariants
|
||||||
NewDebtAuction = types.NewDebtAuction
|
ValidAuctionInvariant = keeper.ValidAuctionInvariant
|
||||||
NewCollateralAuction = types.NewCollateralAuction
|
ValidIndexInvariant = keeper.ValidIndexInvariant
|
||||||
NewWeightedAddresses = types.NewWeightedAddresses
|
DefaultGenesisState = types.DefaultGenesisState
|
||||||
RegisterCodec = types.RegisterCodec
|
DefaultParams = types.DefaultParams
|
||||||
ErrInvalidInitialAuctionID = types.ErrInvalidInitialAuctionID
|
GetAuctionByTimeKey = types.GetAuctionByTimeKey
|
||||||
ErrInvalidModulePermissions = types.ErrInvalidModulePermissions
|
GetAuctionKey = types.GetAuctionKey
|
||||||
ErrUnrecognizedAuctionType = types.ErrUnrecognizedAuctionType
|
NewAuctionWithPhase = types.NewAuctionWithPhase
|
||||||
ErrAuctionNotFound = types.ErrAuctionNotFound
|
NewCollateralAuction = types.NewCollateralAuction
|
||||||
ErrAuctionHasNotExpired = types.ErrAuctionHasNotExpired
|
NewDebtAuction = types.NewDebtAuction
|
||||||
ErrAuctionHasExpired = types.ErrAuctionHasExpired
|
NewGenesisState = types.NewGenesisState
|
||||||
ErrInvalidBidDenom = types.ErrInvalidBidDenom
|
NewMsgPlaceBid = types.NewMsgPlaceBid
|
||||||
ErrInvalidLotDenom = types.ErrInvalidLotDenom
|
NewParams = types.NewParams
|
||||||
ErrBidTooSmall = types.ErrBidTooSmall
|
NewQueryAllAuctionParams = types.NewQueryAllAuctionParams
|
||||||
ErrBidTooLarge = types.ErrBidTooLarge
|
NewSurplusAuction = types.NewSurplusAuction
|
||||||
ErrLotTooSmall = types.ErrLotTooSmall
|
NewWeightedAddresses = types.NewWeightedAddresses
|
||||||
ErrLotTooLarge = types.ErrLotTooLarge
|
ParamKeyTable = types.ParamKeyTable
|
||||||
ErrCollateralAuctionIsInReversePhase = types.ErrCollateralAuctionIsInReversePhase
|
RegisterCodec = types.RegisterCodec
|
||||||
ErrCollateralAuctionIsInForwardPhase = types.ErrCollateralAuctionIsInForwardPhase
|
Uint64FromBytes = types.Uint64FromBytes
|
||||||
NewGenesisState = types.NewGenesisState
|
Uint64ToBytes = types.Uint64ToBytes
|
||||||
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
|
AuctionByTimeKeyPrefix = types.AuctionByTimeKeyPrefix
|
||||||
ModuleCdc = types.ModuleCdc
|
AuctionKeyPrefix = types.AuctionKeyPrefix
|
||||||
AuctionKeyPrefix = types.AuctionKeyPrefix
|
DefaultIncrement = types.DefaultIncrement
|
||||||
AuctionByTimeKeyPrefix = types.AuctionByTimeKeyPrefix
|
DistantFuture = types.DistantFuture
|
||||||
NextAuctionIDKey = types.NextAuctionIDKey
|
ErrAuctionHasExpired = types.ErrAuctionHasExpired
|
||||||
DefaultIncrement = types.DefaultIncrement
|
ErrAuctionHasNotExpired = types.ErrAuctionHasNotExpired
|
||||||
KeyBidDuration = types.KeyBidDuration
|
ErrAuctionNotFound = types.ErrAuctionNotFound
|
||||||
KeyMaxAuctionDuration = types.KeyMaxAuctionDuration
|
ErrBidTooLarge = types.ErrBidTooLarge
|
||||||
KeyIncrementSurplus = types.KeyIncrementSurplus
|
ErrBidTooSmall = types.ErrBidTooSmall
|
||||||
KeyIncrementDebt = types.KeyIncrementDebt
|
ErrInvalidBidDenom = types.ErrInvalidBidDenom
|
||||||
KeyIncrementCollateral = types.KeyIncrementCollateral
|
ErrInvalidInitialAuctionID = types.ErrInvalidInitialAuctionID
|
||||||
|
ErrInvalidLotDenom = types.ErrInvalidLotDenom
|
||||||
|
ErrLotTooLarge = types.ErrLotTooLarge
|
||||||
|
ErrLotTooSmall = types.ErrLotTooSmall
|
||||||
|
ErrUnrecognizedAuctionType = types.ErrUnrecognizedAuctionType
|
||||||
|
KeyBidDuration = types.KeyBidDuration
|
||||||
|
KeyIncrementCollateral = types.KeyIncrementCollateral
|
||||||
|
KeyIncrementDebt = types.KeyIncrementDebt
|
||||||
|
KeyIncrementSurplus = types.KeyIncrementSurplus
|
||||||
|
KeyMaxAuctionDuration = types.KeyMaxAuctionDuration
|
||||||
|
ModuleCdc = types.ModuleCdc
|
||||||
|
NextAuctionIDKey = types.NextAuctionIDKey
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Keeper = keeper.Keeper
|
Keeper = keeper.Keeper
|
||||||
Auction = types.Auction
|
Auction = types.Auction
|
||||||
|
AuctionWithPhase = types.AuctionWithPhase
|
||||||
Auctions = types.Auctions
|
Auctions = types.Auctions
|
||||||
BaseAuction = types.BaseAuction
|
BaseAuction = types.BaseAuction
|
||||||
SurplusAuction = types.SurplusAuction
|
|
||||||
DebtAuction = types.DebtAuction
|
|
||||||
CollateralAuction = types.CollateralAuction
|
CollateralAuction = types.CollateralAuction
|
||||||
WeightedAddresses = types.WeightedAddresses
|
DebtAuction = types.DebtAuction
|
||||||
SupplyKeeper = types.SupplyKeeper
|
|
||||||
GenesisAuction = types.GenesisAuction
|
GenesisAuction = types.GenesisAuction
|
||||||
GenesisAuctions = types.GenesisAuctions
|
GenesisAuctions = types.GenesisAuctions
|
||||||
GenesisState = types.GenesisState
|
GenesisState = types.GenesisState
|
||||||
MsgPlaceBid = types.MsgPlaceBid
|
MsgPlaceBid = types.MsgPlaceBid
|
||||||
Params = types.Params
|
Params = types.Params
|
||||||
QueryAuctionParams = types.QueryAuctionParams
|
|
||||||
QueryAllAuctionParams = types.QueryAllAuctionParams
|
QueryAllAuctionParams = types.QueryAllAuctionParams
|
||||||
AuctionWithPhase = types.AuctionWithPhase
|
QueryAuctionParams = types.QueryAuctionParams
|
||||||
|
SupplyKeeper = types.SupplyKeeper
|
||||||
|
SurplusAuction = types.SurplusAuction
|
||||||
|
WeightedAddresses = types.WeightedAddresses
|
||||||
)
|
)
|
||||||
|
@ -9,17 +9,20 @@ import (
|
|||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _, testAddrs = app.GeneratePrivKeyAddressPairs(2)
|
||||||
var testTime = time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
var testTime = time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||||
var testAuction = auction.NewCollateralAuction(
|
var testAuction = auction.NewCollateralAuction(
|
||||||
"seller",
|
"seller",
|
||||||
c("lotdenom", 10),
|
c("lotdenom", 10),
|
||||||
testTime,
|
testTime,
|
||||||
c("biddenom", 1000),
|
c("biddenom", 1000),
|
||||||
auction.WeightedAddresses{},
|
auction.WeightedAddresses{Addresses: testAddrs, Weights: []sdk.Int{sdk.OneInt(), sdk.OneInt()}},
|
||||||
c("debt", 1000),
|
c("debt", 1000),
|
||||||
).WithID(3).(auction.GenesisAuction)
|
).WithID(3).(auction.GenesisAuction)
|
||||||
|
|
||||||
|
@ -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
|
||||||
@ -35,8 +36,8 @@ func (k Keeper) StartSurplusAuction(ctx sdk.Context, seller string, lot sdk.Coin
|
|||||||
types.EventTypeAuctionStart,
|
types.EventTypeAuctionStart,
|
||||||
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.AttributeKeyBid, auction.Bid.String()),
|
||||||
sdk.NewAttribute(types.AttributeKeyLotDenom, auction.Lot.Denom),
|
sdk.NewAttribute(types.AttributeKeyLot, auction.Lot.String()),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return auctionID, nil
|
return auctionID, nil
|
||||||
@ -50,14 +51,16 @@ 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) {
|
||||||
return 0, sdkerrors.Wrap(types.ErrInvalidModulePermissions, supply.Minter)
|
panic(fmt.Errorf("module '%s' does not have '%s' permission", buyer, 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
|
||||||
@ -73,8 +76,8 @@ func (k Keeper) StartDebtAuction(ctx sdk.Context, buyer string, bid sdk.Coin, in
|
|||||||
types.EventTypeAuctionStart,
|
types.EventTypeAuctionStart,
|
||||||
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.AttributeKeyBid, auction.Bid.String()),
|
||||||
sdk.NewAttribute(types.AttributeKeyLotDenom, auction.Lot.Denom),
|
sdk.NewAttribute(types.AttributeKeyLot, auction.Lot.String()),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return auctionID, nil
|
return auctionID, nil
|
||||||
@ -98,6 +101,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
|
||||||
@ -117,8 +121,9 @@ func (k Keeper) StartCollateralAuction(
|
|||||||
types.EventTypeAuctionStart,
|
types.EventTypeAuctionStart,
|
||||||
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.AttributeKeyBid, auction.Bid.String()),
|
||||||
sdk.NewAttribute(types.AttributeKeyLotDenom, auction.Lot.Denom),
|
sdk.NewAttribute(types.AttributeKeyLot, auction.Lot.String()),
|
||||||
|
sdk.NewAttribute(types.AttributeKeyMaxBid, auction.MaxBid.String()),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return auctionID, nil
|
return auctionID, nil
|
||||||
@ -218,7 +223,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,7 +238,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() {
|
||||||
return a, sdkerrors.Wrapf(types.ErrCollateralAuctionIsInReversePhase, "%d", a.ID)
|
panic("cannot place forward bid on auction in reverse phase")
|
||||||
}
|
}
|
||||||
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
|
||||||
sdk.MaxInt(
|
sdk.MaxInt(
|
||||||
@ -294,7 +299,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,7 +314,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() {
|
||||||
return a, sdkerrors.Wrapf(types.ErrCollateralAuctionIsInForwardPhase, "%d", a.ID)
|
panic("cannot place reverse bid on auction in forward phase")
|
||||||
}
|
}
|
||||||
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
|
||||||
sdk.MaxInt(
|
sdk.MaxInt(
|
||||||
@ -336,13 +341,18 @@ 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.
|
// Note: splitting an integer amount across weighted buckets results in small errors.
|
||||||
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 {
|
||||||
|
// if the payout amount is 0, don't send 0 coins
|
||||||
|
if !payout.IsPositive() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.LotReturns.Addresses[i], sdk.NewCoins(payout))
|
err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.LotReturns.Addresses[i], sdk.NewCoins(payout))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return a, err
|
return a, err
|
||||||
@ -363,7 +373,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 +439,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())),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -473,6 +483,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())),
|
||||||
|
sdk.NewAttribute(types.AttributeKeyCloseBlock, fmt.Sprintf("%d", ctx.BlockHeight())),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return nil
|
return nil
|
||||||
@ -480,14 +491,17 @@ 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 {
|
||||||
return err
|
panic(fmt.Errorf("could not mint coins: %w", 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 {
|
||||||
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 {
|
||||||
@ -499,6 +513,7 @@ 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 {
|
||||||
return err
|
return err
|
||||||
@ -508,10 +523,13 @@ 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 {
|
||||||
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 {
|
||||||
@ -547,11 +565,6 @@ func earliestTime(t1, t2 time.Time) time.Time {
|
|||||||
|
|
||||||
// splitCoinIntoWeightedBuckets divides up some amount of coins according to some weights.
|
// splitCoinIntoWeightedBuckets divides up some amount of coins according to some weights.
|
||||||
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 {
|
|
||||||
if bucket.IsNegative() {
|
|
||||||
return nil, fmt.Errorf("cannot split %s into bucket with negative weight (%s)", coin.String(), bucket.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
amounts := splitIntIntoWeightedBuckets(coin.Amount, buckets)
|
amounts := splitIntIntoWeightedBuckets(coin.Amount, buckets)
|
||||||
result := make([]sdk.Coin, len(amounts))
|
result := make([]sdk.Coin, len(amounts))
|
||||||
for i, a := range amounts {
|
for i, a := range amounts {
|
||||||
|
@ -128,7 +128,7 @@ func (k Keeper) DeleteAuction(ctx sdk.Context, auctionID uint64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InsertIntoByTimeIndex adds an auction ID and end time into the byTime index.
|
// InsertIntoByTimeIndex adds an auction ID and end time into the byTime index.
|
||||||
func (k Keeper) InsertIntoByTimeIndex(ctx sdk.Context, endTime time.Time, auctionID uint64) { // TODO make private, and find way to make tests work
|
func (k Keeper) InsertIntoByTimeIndex(ctx sdk.Context, endTime time.Time, auctionID uint64) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.AuctionByTimeKeyPrefix)
|
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.AuctionByTimeKeyPrefix)
|
||||||
store.Set(types.GetAuctionByTimeKey(endTime, auctionID), types.Uint64ToBytes(auctionID))
|
store.Set(types.GetAuctionByTimeKey(endTime, auctionID), types.Uint64ToBytes(auctionID))
|
||||||
}
|
}
|
||||||
|
@ -7,41 +7,52 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// splitIntIntoWeightedBuckets divides an initial +ve integer among several buckets in proportion to the buckets' weights
|
// splitIntIntoWeightedBuckets divides an initial +ve integer among several buckets in proportion to the buckets' weights
|
||||||
// It uses the largest remainder method:
|
// It uses the largest remainder method: 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
|
// Limit input to +ve numbers as algorithm hasn't been scoped to work with -ve numbers.
|
||||||
if amount.IsNegative() {
|
if amount.IsNegative() {
|
||||||
panic("negative amount")
|
panic("negative amount")
|
||||||
}
|
}
|
||||||
|
if len(buckets) < 1 {
|
||||||
|
panic("no buckets")
|
||||||
|
}
|
||||||
for _, bucket := range buckets {
|
for _, bucket := range buckets {
|
||||||
if bucket.IsNegative() {
|
if bucket.IsNegative() {
|
||||||
panic("negative bucket")
|
panic("negative bucket")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
totalWeights := totalInts(buckets...)
|
// 1) Split the amount by weights, recording whole number part and remainder
|
||||||
|
|
||||||
|
totalWeights := totalInts(buckets...)
|
||||||
|
if !totalWeights.IsPositive() {
|
||||||
|
panic("total weights must sum to > 0")
|
||||||
|
}
|
||||||
|
|
||||||
// split amount by weights, recording whole number part and remainder
|
|
||||||
quotients := make([]quoRem, len(buckets))
|
quotients := make([]quoRem, len(buckets))
|
||||||
for i := range buckets {
|
for i := range buckets {
|
||||||
|
// amount * ( weight/total_weight )
|
||||||
q := amount.Mul(buckets[i]).Quo(totalWeights)
|
q := amount.Mul(buckets[i]).Quo(totalWeights)
|
||||||
r := amount.Mul(buckets[i]).Mod(totalWeights)
|
r := amount.Mul(buckets[i]).Mod(totalWeights)
|
||||||
quotients[i] = quoRem{index: i, quo: q, rem: r}
|
quotients[i] = quoRem{index: i, quo: q, rem: r}
|
||||||
}
|
}
|
||||||
|
|
||||||
// apportion left over to buckets with the highest remainder (to minimize error)
|
// 2) Calculate total left over from remainders, and apportion it to buckets with the highest remainder (to minimize error)
|
||||||
|
|
||||||
|
// sort by decreasing remainder order
|
||||||
sort.Slice(quotients, func(i, j int) bool {
|
sort.Slice(quotients, func(i, j int) bool {
|
||||||
return quotients[i].rem.GT(quotients[j].rem) // decreasing remainder order
|
return quotients[i].rem.GT(quotients[j].rem)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// calculate total left over from remainders
|
||||||
allocated := sdk.ZeroInt()
|
allocated := sdk.ZeroInt()
|
||||||
for _, qr := range quotients {
|
for _, qr := range quotients {
|
||||||
allocated = allocated.Add(qr.quo)
|
allocated = allocated.Add(qr.quo)
|
||||||
}
|
}
|
||||||
leftToAllocate := amount.Sub(allocated)
|
leftToAllocate := amount.Sub(allocated)
|
||||||
|
|
||||||
|
// apportion according to largest remainder
|
||||||
results := make([]sdk.Int, len(quotients))
|
results := make([]sdk.Int, len(quotients))
|
||||||
for _, qr := range quotients {
|
for _, qr := range quotients {
|
||||||
results[qr.index] = qr.quo
|
results[qr.index] = qr.quo
|
||||||
|
@ -10,19 +10,97 @@ import (
|
|||||||
|
|
||||||
func TestSplitIntIntoWeightedBuckets(t *testing.T) {
|
func TestSplitIntIntoWeightedBuckets(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
amount sdk.Int
|
amount sdk.Int
|
||||||
buckets []sdk.Int
|
buckets []sdk.Int
|
||||||
want []sdk.Int
|
want []sdk.Int
|
||||||
|
expectPanic bool
|
||||||
}{
|
}{
|
||||||
{"2split1,1", i(2), is(1, 1), is(1, 1)},
|
{
|
||||||
{"100split1,9", i(100), is(1, 9), is(10, 90)},
|
name: "0split0",
|
||||||
{"7split1,2", i(7), is(1, 2), is(2, 5)},
|
amount: i(0),
|
||||||
{"17split1,1,1", i(17), is(1, 1, 1), is(6, 6, 5)},
|
buckets: is(0),
|
||||||
|
expectPanic: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "5splitnil",
|
||||||
|
amount: i(5),
|
||||||
|
buckets: is(),
|
||||||
|
expectPanic: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "-2split1,1",
|
||||||
|
amount: i(-2),
|
||||||
|
buckets: is(1, 1),
|
||||||
|
expectPanic: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2split1,-1",
|
||||||
|
amount: i(2),
|
||||||
|
buckets: is(1, -1),
|
||||||
|
expectPanic: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "0split0,0,0,1",
|
||||||
|
amount: i(0),
|
||||||
|
buckets: is(0, 0, 0, 1),
|
||||||
|
want: is(0, 0, 0, 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2split1,1",
|
||||||
|
amount: i(2),
|
||||||
|
buckets: is(1, 1),
|
||||||
|
want: is(1, 1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "100split1,9",
|
||||||
|
amount: i(100),
|
||||||
|
buckets: is(1, 9),
|
||||||
|
want: is(10, 90),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "100split9,1",
|
||||||
|
amount: i(100),
|
||||||
|
buckets: is(9, 1),
|
||||||
|
want: is(90, 10),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "7split1,2",
|
||||||
|
amount: i(7),
|
||||||
|
buckets: is(1, 2),
|
||||||
|
want: is(2, 5),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "17split1,1,1",
|
||||||
|
amount: i(17),
|
||||||
|
buckets: is(1, 1, 1),
|
||||||
|
want: is(6, 6, 5),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "10split1000000,1",
|
||||||
|
amount: i(10),
|
||||||
|
buckets: is(1000000, 1),
|
||||||
|
want: is(10, 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "334733353split730777,31547",
|
||||||
|
amount: i(334733353),
|
||||||
|
buckets: is(730777, 31547),
|
||||||
|
want: is(320881194, 13852159),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
got := splitIntIntoWeightedBuckets(tc.amount, tc.buckets)
|
var got []sdk.Int
|
||||||
|
run := func() {
|
||||||
|
got = splitIntIntoWeightedBuckets(tc.amount, tc.buckets)
|
||||||
|
}
|
||||||
|
if tc.expectPanic {
|
||||||
|
require.Panics(t, run)
|
||||||
|
} else {
|
||||||
|
require.NotPanics(t, run)
|
||||||
|
}
|
||||||
|
|
||||||
require.Equal(t, tc.want, got)
|
require.Equal(t, tc.want, got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,13 @@ The `x/auction` module emits the following events:
|
|||||||
|
|
||||||
## Triggered By Other Modules
|
## Triggered By Other Modules
|
||||||
|
|
||||||
| Type | Attribute Key | Attribute Value |
|
| Type | Attribute Key | Attribute Value |
|
||||||
|---------------|---------------|---------------------|
|
|---------------|---------------|-----------------|
|
||||||
| auction_start | auction_id | {auction ID} |
|
| auction_start | auction_id | {auction ID} |
|
||||||
| auction_start | auction_type | {auction type} |
|
| auction_start | auction_type | {auction type} |
|
||||||
| auction_start | lot_denom | {auction lot denom} |
|
| auction_start | lot | {coin amount} |
|
||||||
| auction_start | bid_denom | {auction bid denom} |
|
| auction_start | bid | {coin amount} |
|
||||||
|
| auction_start | max_bid | {coin amount} |
|
||||||
|
|
||||||
## Handlers
|
## Handlers
|
||||||
|
|
||||||
@ -19,8 +20,8 @@ The `x/auction` module emits the following events:
|
|||||||
|-------------|---------------|--------------------|
|
|-------------|---------------|--------------------|
|
||||||
| auction_bid | auction_id | {auction ID} |
|
| auction_bid | auction_id | {auction ID} |
|
||||||
| auction_bid | bidder | {latest bidder} |
|
| auction_bid | bidder | {latest bidder} |
|
||||||
| auction_bid | bid_amount | {coin amount} |
|
| auction_bid | bid | {coin amount} |
|
||||||
| auction_bid | lot_amount | {coin amount} |
|
| auction_bid | lot | {coin amount} |
|
||||||
| auction_bid | end_time | {auction end time} |
|
| auction_bid | end_time | {auction end time} |
|
||||||
| message | module | auction |
|
| message | module | auction |
|
||||||
| message | sender | {sender address} |
|
| message | sender | {sender address} |
|
||||||
@ -30,3 +31,4 @@ The `x/auction` module emits the following events:
|
|||||||
| Type | Attribute Key | Attribute Value |
|
| Type | Attribute Key | Attribute Value |
|
||||||
|---------------|---------------|-----------------|
|
|---------------|---------------|-----------------|
|
||||||
| auction_close | auction_id | {auction ID} |
|
| auction_close | auction_id | {auction ID} |
|
||||||
|
| auction_close | close_block | {block height} |
|
||||||
|
@ -287,15 +287,23 @@ func NewWeightedAddresses(addrs []sdk.AccAddress, weights []sdk.Int) (WeightedAd
|
|||||||
return wa, nil
|
return wa, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate checks for that the weights are not negative and that lengths match.
|
// Validate checks for that the weights are not negative, not all zero, and the lengths match.
|
||||||
func (wa WeightedAddresses) Validate() error {
|
func (wa WeightedAddresses) Validate() error {
|
||||||
|
if len(wa.Weights) < 1 {
|
||||||
|
return fmt.Errorf("must be at least 1 weighted address")
|
||||||
|
}
|
||||||
if len(wa.Addresses) != len(wa.Weights) {
|
if len(wa.Addresses) != len(wa.Weights) {
|
||||||
return fmt.Errorf("number of addresses doesn't match number of weights, %d ≠ %d", len(wa.Addresses), len(wa.Weights))
|
return fmt.Errorf("number of addresses doesn't match number of weights, %d ≠ %d", len(wa.Addresses), len(wa.Weights))
|
||||||
}
|
}
|
||||||
|
totalWeight := sdk.ZeroInt()
|
||||||
for _, w := range wa.Weights {
|
for _, w := range wa.Weights {
|
||||||
if w.IsNegative() {
|
if w.IsNegative() {
|
||||||
return fmt.Errorf("weights contain a negative amount: %s", w)
|
return fmt.Errorf("weights contain a negative amount: %s", w)
|
||||||
}
|
}
|
||||||
|
totalWeight = totalWeight.Add(w)
|
||||||
|
}
|
||||||
|
if !totalWeight.IsPositive() {
|
||||||
|
return fmt.Errorf("total weight must be positive")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -24,48 +25,65 @@ const (
|
|||||||
TestAccAddress2 = "kava1pdfav2cjhry9k79nu6r8kgknnjtq6a7rcr0qlr"
|
TestAccAddress2 = "kava1pdfav2cjhry9k79nu6r8kgknnjtq6a7rcr0qlr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func d(amount string) sdk.Dec { return sdk.MustNewDecFromStr(amount) }
|
||||||
|
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
|
||||||
|
func i(n int64) sdk.Int { return sdk.NewInt(n) }
|
||||||
|
func is(ns ...int64) (is []sdk.Int) {
|
||||||
|
for _, n := range ns {
|
||||||
|
is = append(is, sdk.NewInt(n))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewWeightedAddresses(t *testing.T) {
|
func TestNewWeightedAddresses(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
addresses []sdk.AccAddress
|
addresses []sdk.AccAddress
|
||||||
weights []sdk.Int
|
weights []sdk.Int
|
||||||
expectpass bool
|
expectedErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"normal",
|
name: "normal",
|
||||||
[]sdk.AccAddress{
|
addresses: []sdk.AccAddress{
|
||||||
sdk.AccAddress([]byte(TestAccAddress1)),
|
sdk.AccAddress([]byte(TestAccAddress1)),
|
||||||
sdk.AccAddress([]byte(TestAccAddress2)),
|
sdk.AccAddress([]byte(TestAccAddress2)),
|
||||||
},
|
},
|
||||||
[]sdk.Int{
|
weights: is(6, 8),
|
||||||
sdk.NewInt(6),
|
expectedErr: nil,
|
||||||
sdk.NewInt(8),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"mismatched",
|
name: "mismatched",
|
||||||
[]sdk.AccAddress{
|
addresses: []sdk.AccAddress{
|
||||||
sdk.AccAddress([]byte(TestAccAddress1)),
|
sdk.AccAddress([]byte(TestAccAddress1)),
|
||||||
sdk.AccAddress([]byte(TestAccAddress2)),
|
sdk.AccAddress([]byte(TestAccAddress2)),
|
||||||
},
|
},
|
||||||
[]sdk.Int{
|
weights: is(6),
|
||||||
sdk.NewInt(6),
|
expectedErr: fmt.Errorf("number of addresses doesn't match number of weights, %d ≠ %d", 2, 1),
|
||||||
},
|
|
||||||
false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"negativeWeight",
|
name: "negativeWeight",
|
||||||
[]sdk.AccAddress{
|
addresses: []sdk.AccAddress{
|
||||||
sdk.AccAddress([]byte(TestAccAddress1)),
|
sdk.AccAddress([]byte(TestAccAddress1)),
|
||||||
sdk.AccAddress([]byte(TestAccAddress2)),
|
sdk.AccAddress([]byte(TestAccAddress2)),
|
||||||
},
|
},
|
||||||
[]sdk.Int{
|
weights: is(6, -8),
|
||||||
sdk.NewInt(6),
|
expectedErr: fmt.Errorf("weights contain a negative amount: %s", i(-8)),
|
||||||
sdk.NewInt(-8),
|
},
|
||||||
|
{
|
||||||
|
name: "zero total weights",
|
||||||
|
addresses: []sdk.AccAddress{
|
||||||
|
sdk.AccAddress([]byte(TestAccAddress1)),
|
||||||
|
sdk.AccAddress([]byte(TestAccAddress2)),
|
||||||
},
|
},
|
||||||
false,
|
weights: is(0, 0),
|
||||||
|
expectedErr: fmt.Errorf("total weight must be positive"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no weights",
|
||||||
|
addresses: nil,
|
||||||
|
weights: nil,
|
||||||
|
expectedErr: fmt.Errorf("must be at least 1 weighted address"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,27 +93,16 @@ func TestNewWeightedAddresses(t *testing.T) {
|
|||||||
// Attempt to instantiate new WeightedAddresses
|
// Attempt to instantiate new WeightedAddresses
|
||||||
weightedAddresses, err := NewWeightedAddresses(tc.addresses, tc.weights)
|
weightedAddresses, err := NewWeightedAddresses(tc.addresses, tc.weights)
|
||||||
|
|
||||||
if tc.expectpass {
|
if tc.expectedErr != nil {
|
||||||
// Confirm there is no error
|
// Confirm the error
|
||||||
require.Nil(t, err)
|
require.EqualError(t, err, tc.expectedErr.Error())
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
// Check addresses, weights
|
// Check addresses, weights
|
||||||
require.Equal(t, tc.addresses, weightedAddresses.Addresses)
|
require.Equal(t, tc.addresses, weightedAddresses.Addresses)
|
||||||
require.Equal(t, tc.weights, weightedAddresses.Weights)
|
require.Equal(t, tc.weights, weightedAddresses.Weights)
|
||||||
} else {
|
|
||||||
// Confirm that there is an error
|
|
||||||
require.NotNil(t, err)
|
|
||||||
|
|
||||||
switch tc.name {
|
|
||||||
case "mismatched":
|
|
||||||
require.Contains(t, err.Error(), "number of addresses doesn't match number of weights")
|
|
||||||
case "negativeWeight":
|
|
||||||
require.Contains(t, err.Error(), "weights contain a negative amount")
|
|
||||||
default:
|
|
||||||
// Unexpected error state
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,30 +7,24 @@ import sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|||||||
var (
|
var (
|
||||||
// ErrInvalidInitialAuctionID error for when the initial auction ID hasn't been set
|
// ErrInvalidInitialAuctionID error for when the initial auction ID hasn't been set
|
||||||
ErrInvalidInitialAuctionID = sdkerrors.Register(ModuleName, 2, "initial auction ID hasn't been set")
|
ErrInvalidInitialAuctionID = sdkerrors.Register(ModuleName, 2, "initial auction ID hasn't been set")
|
||||||
// ErrInvalidModulePermissions error for when module doesn't have valid permissions
|
|
||||||
ErrInvalidModulePermissions = sdkerrors.Register(ModuleName, 3, "module does not have required permission")
|
|
||||||
// ErrUnrecognizedAuctionType error for unrecognized auction type
|
// ErrUnrecognizedAuctionType error for unrecognized auction type
|
||||||
ErrUnrecognizedAuctionType = sdkerrors.Register(ModuleName, 4, "unrecognized auction type")
|
ErrUnrecognizedAuctionType = sdkerrors.Register(ModuleName, 3, "unrecognized auction type")
|
||||||
// ErrAuctionNotFound error for when an auction is not found
|
// ErrAuctionNotFound error for when an auction is not found
|
||||||
ErrAuctionNotFound = sdkerrors.Register(ModuleName, 5, "auction not found")
|
ErrAuctionNotFound = sdkerrors.Register(ModuleName, 4, "auction not found")
|
||||||
// ErrAuctionHasNotExpired error for attempting to close an auction that has not passed its end time
|
// ErrAuctionHasNotExpired error for attempting to close an auction that has not passed its end time
|
||||||
ErrAuctionHasNotExpired = sdkerrors.Register(ModuleName, 6, "auction can't be closed as curent block time has not passed auction end time")
|
ErrAuctionHasNotExpired = sdkerrors.Register(ModuleName, 5, "auction can't be closed as curent block time has not passed auction end time")
|
||||||
// ErrAuctionHasExpired error for when an auction is closed and unavailable for bidding
|
// ErrAuctionHasExpired error for when an auction is closed and unavailable for bidding
|
||||||
ErrAuctionHasExpired = sdkerrors.Register(ModuleName, 7, "auction has closed")
|
ErrAuctionHasExpired = sdkerrors.Register(ModuleName, 6, "auction has closed")
|
||||||
// ErrInvalidBidDenom error for when bid denom doesn't match auction bid denom
|
// ErrInvalidBidDenom error for when bid denom doesn't match auction bid denom
|
||||||
ErrInvalidBidDenom = sdkerrors.Register(ModuleName, 8, "bid denom doesn't match auction bid denom")
|
ErrInvalidBidDenom = sdkerrors.Register(ModuleName, 7, "bid denom doesn't match auction bid denom")
|
||||||
// ErrInvalidLotDenom error for when lot denom doesn't match auction lot denom
|
// ErrInvalidLotDenom error for when lot denom doesn't match auction lot denom
|
||||||
ErrInvalidLotDenom = sdkerrors.Register(ModuleName, 9, "lot denom doesn't match auction lot denom")
|
ErrInvalidLotDenom = sdkerrors.Register(ModuleName, 8, "lot denom doesn't match auction lot denom")
|
||||||
// ErrBidTooSmall error for when bid is not greater than auction's min bid amount
|
// ErrBidTooSmall error for when bid is not greater than auction's min bid amount
|
||||||
ErrBidTooSmall = sdkerrors.Register(ModuleName, 10, "bid is not greater than auction's min new bid amount")
|
ErrBidTooSmall = sdkerrors.Register(ModuleName, 9, "bid is not greater than auction's min new bid amount")
|
||||||
// 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
|
||||||
ErrBidTooLarge = sdkerrors.Register(ModuleName, 11, "bid is greater than auction's max bid")
|
ErrBidTooLarge = sdkerrors.Register(ModuleName, 10, "bid is greater than auction's max bid")
|
||||||
// ErrLotTooSmall error for when lot is less than zero
|
// ErrLotTooSmall error for when lot is less than zero
|
||||||
ErrLotTooSmall = sdkerrors.Register(ModuleName, 12, "lot is not greater than auction's min new lot amount")
|
ErrLotTooSmall = sdkerrors.Register(ModuleName, 11, "lot is not greater than auction's min new lot amount")
|
||||||
// ErrLotTooLarge error for when lot is not smaller than auction's max new lot amount
|
// ErrLotTooLarge error for when lot is not smaller than auction's max new lot amount
|
||||||
ErrLotTooLarge = sdkerrors.Register(ModuleName, 13, "lot is greater than auction's max new lot amount")
|
ErrLotTooLarge = sdkerrors.Register(ModuleName, 12, "lot is greater than auction's max new lot amount")
|
||||||
// ErrCollateralAuctionIsInReversePhase error for when attempting to place a forward bid on a collateral auction in reverse phase
|
|
||||||
ErrCollateralAuctionIsInReversePhase = sdkerrors.Register(ModuleName, 14, "invalid bid: auction is in reverse phase")
|
|
||||||
// ErrCollateralAuctionIsInForwardPhase error for when attempting to place a reverse bid on a collateral auction in forward phase
|
|
||||||
ErrCollateralAuctionIsInForwardPhase = sdkerrors.Register(ModuleName, 15, "invalid bid: auction is in forward phase")
|
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
// Events for auction module
|
// Events for the module
|
||||||
const (
|
const (
|
||||||
EventTypeAuctionStart = "auction_start"
|
EventTypeAuctionStart = "auction_start"
|
||||||
EventTypeAuctionBid = "auction_bid"
|
EventTypeAuctionBid = "auction_bid"
|
||||||
@ -10,9 +10,9 @@ const (
|
|||||||
AttributeKeyAuctionID = "auction_id"
|
AttributeKeyAuctionID = "auction_id"
|
||||||
AttributeKeyAuctionType = "auction_type"
|
AttributeKeyAuctionType = "auction_type"
|
||||||
AttributeKeyBidder = "bidder"
|
AttributeKeyBidder = "bidder"
|
||||||
AttributeKeyBidDenom = "bid_denom"
|
AttributeKeyLot = "lot"
|
||||||
AttributeKeyLotDenom = "lot_denom"
|
AttributeKeyMaxBid = "max_bid"
|
||||||
AttributeKeyBidAmount = "bid_amount"
|
AttributeKeyBid = "bid"
|
||||||
AttributeKeyLotAmount = "lot_amount"
|
|
||||||
AttributeKeyEndTime = "end_time"
|
AttributeKeyEndTime = "end_time"
|
||||||
|
AttributeKeyCloseBlock = "close_block"
|
||||||
)
|
)
|
||||||
|
@ -76,7 +76,7 @@ func (gs GenesisState) Validate() error {
|
|||||||
ids[a.GetID()] = true
|
ids[a.GetID()] = true
|
||||||
|
|
||||||
if a.GetID() >= gs.NextAuctionID {
|
if a.GetID() >= gs.NextAuctionID {
|
||||||
return fmt.Errorf("found auction ID >= the nextAuctionID (%d >= %d)", a.GetID(), gs.NextAuctionID)
|
return fmt.Errorf("found auction ID ≥ the nextAuctionID (%d ≥ %d)", a.GetID(), gs.NextAuctionID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -39,5 +39,3 @@ func TestMsgPlaceBid_ValidateBasic(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
|
|
||||||
|
@ -5,8 +5,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParams_Validate(t *testing.T) {
|
func TestParams_Validate(t *testing.T) {
|
||||||
@ -105,5 +103,3 @@ func TestParams_Validate(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func d(amount string) sdk.Dec { return sdk.MustNewDecFromStr(amount) }
|
|
||||||
|
@ -11,98 +11,15 @@ const (
|
|||||||
dump = 100
|
dump = 100
|
||||||
)
|
)
|
||||||
|
|
||||||
type partialDeposit struct {
|
|
||||||
Depositor sdk.AccAddress
|
|
||||||
Amount sdk.Coin
|
|
||||||
DebtShare sdk.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPartialDeposit(depositor sdk.AccAddress, amount sdk.Coin, ds sdk.Int) partialDeposit {
|
|
||||||
return partialDeposit{
|
|
||||||
Depositor: depositor,
|
|
||||||
Amount: amount,
|
|
||||||
DebtShare: ds,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type partialDeposits []partialDeposit
|
|
||||||
|
|
||||||
func (pd partialDeposits) SumCollateral() (sum sdk.Int) {
|
|
||||||
sum = sdk.ZeroInt()
|
|
||||||
for _, d := range pd {
|
|
||||||
sum = sum.Add(d.Amount.Amount)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pd partialDeposits) SumDebt() (sum sdk.Int) {
|
|
||||||
sum = sdk.ZeroInt()
|
|
||||||
for _, d := range pd {
|
|
||||||
sum = sum.Add(d.DebtShare)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuctionCollateral creates auctions from the input deposits which attempt to raise the corresponding amount of debt
|
// AuctionCollateral creates auctions from the input deposits which attempt to raise the corresponding amount of debt
|
||||||
func (k Keeper) AuctionCollateral(ctx sdk.Context, deposits types.Deposits, debt sdk.Int, bidDenom string) error {
|
func (k Keeper) AuctionCollateral(ctx sdk.Context, deposits types.Deposits, debt sdk.Int, bidDenom string) error {
|
||||||
auctionSize := k.getAuctionSize(ctx, deposits[0].Amount.Denom)
|
|
||||||
partialAuctionDeposits := partialDeposits{}
|
|
||||||
totalCollateral := deposits.SumCollateral()
|
|
||||||
for totalCollateral.GT(sdk.ZeroInt()) {
|
|
||||||
for i, dep := range deposits {
|
|
||||||
if dep.Amount.IsZero() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
collateralAmount := dep.Amount.Amount
|
|
||||||
collateralDenom := dep.Amount.Denom
|
|
||||||
// create auctions from individual deposits that are larger than the auction size
|
|
||||||
debtChange, collateralChange, err := k.CreateAuctionsFromDeposit(ctx, dep, debt, totalCollateral, auctionSize, bidDenom)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
debt = debt.Sub(debtChange)
|
|
||||||
totalCollateral = totalCollateral.Sub(collateralChange)
|
|
||||||
dep.Amount = sdk.NewCoin(collateralDenom, collateralAmount.Sub(collateralChange))
|
|
||||||
collateralAmount = collateralAmount.Sub(collateralChange)
|
|
||||||
// if there is leftover collateral that is less than a lot
|
|
||||||
if !dep.Amount.IsZero() {
|
|
||||||
// figure out how much debt this deposit accounts for
|
|
||||||
// (depositCollateral / totalCollateral) * totalDebtFromCDP
|
|
||||||
debtCoveredByDeposit := (collateralAmount.Quo(totalCollateral)).Mul(debt)
|
|
||||||
// if adding this deposit to the other partial deposits is less than a lot
|
|
||||||
if (partialAuctionDeposits.SumCollateral().Add(collateralAmount)).LT(auctionSize) {
|
|
||||||
// append the deposit to the partial deposits and zero out the deposit
|
|
||||||
pd := newPartialDeposit(dep.Depositor, dep.Amount, debtCoveredByDeposit)
|
|
||||||
partialAuctionDeposits = append(partialAuctionDeposits, pd)
|
|
||||||
dep.Amount = sdk.NewCoin(collateralDenom, sdk.ZeroInt())
|
|
||||||
} else {
|
|
||||||
// if the sum of partial deposits now makes a lot
|
|
||||||
partialCollateral := sdk.NewCoin(collateralDenom, auctionSize.Sub(partialAuctionDeposits.SumCollateral()))
|
|
||||||
partialAmount := partialCollateral.Amount
|
|
||||||
partialDebt := (partialAmount.Quo(collateralAmount)).Mul(debtCoveredByDeposit)
|
|
||||||
|
|
||||||
// create a partial deposit from the deposit
|
auctionSize := k.getAuctionSize(ctx, deposits[0].Amount.Denom)
|
||||||
partialDep := newPartialDeposit(dep.Depositor, partialCollateral, partialDebt)
|
totalCollateral := deposits.SumCollateral()
|
||||||
// append it to the partial deposits
|
for _, deposit := range deposits {
|
||||||
partialAuctionDeposits = append(partialAuctionDeposits, partialDep)
|
|
||||||
// create an auction from the partial deposits
|
debtCoveredByDeposit := (sdk.NewDecFromInt(deposit.Amount.Amount).Quo(sdk.NewDecFromInt(totalCollateral))).Mul(sdk.NewDecFromInt(debt)).RoundInt()
|
||||||
debtChange, collateralChange, err := k.CreateAuctionFromPartialDeposits(ctx, partialAuctionDeposits, debt, totalCollateral, auctionSize, bidDenom)
|
err := k.CreateAuctionsFromDeposit(ctx, deposit.Amount, deposit.Depositor, debtCoveredByDeposit, auctionSize, bidDenom)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
debt = debt.Sub(debtChange)
|
|
||||||
totalCollateral = totalCollateral.Sub(collateralChange)
|
|
||||||
// reset partial deposits and update the deposit amount
|
|
||||||
partialAuctionDeposits = partialDeposits{}
|
|
||||||
dep.Amount = sdk.NewCoin(collateralDenom, collateralAmount.Sub(partialAmount))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deposits[i] = dep
|
|
||||||
totalCollateral = deposits.SumCollateral()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if partialAuctionDeposits.SumCollateral().GT(sdk.ZeroInt()) {
|
|
||||||
_, _, err := k.CreateAuctionFromPartialDeposits(ctx, partialAuctionDeposits, debt, totalCollateral, partialAuctionDeposits.SumCollateral(), bidDenom)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -110,54 +27,38 @@ func (k Keeper) AuctionCollateral(ctx sdk.Context, deposits types.Deposits, debt
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateAuctionsFromDeposit creates auctions from the input deposit until there is less than auctionSize left on the deposit
|
// CreateAuctionsFromDeposit creates auctions from the input deposit
|
||||||
func (k Keeper) CreateAuctionsFromDeposit(
|
func (k Keeper) CreateAuctionsFromDeposit(
|
||||||
ctx sdk.Context, dep types.Deposit, debt sdk.Int, totalCollateral sdk.Int, auctionSize sdk.Int,
|
ctx sdk.Context, collateral sdk.Coin, returnAddr sdk.AccAddress, debt, auctionSize sdk.Int,
|
||||||
principalDenom string) (debtChange sdk.Int, collateralChange sdk.Int, err error) {
|
principalDenom string) (err error) {
|
||||||
debtChange = sdk.ZeroInt()
|
|
||||||
collateralChange = sdk.ZeroInt()
|
amountToAuction := collateral.Amount
|
||||||
depositAmount := dep.Amount.Amount
|
totalCollateralAmount := collateral.Amount
|
||||||
depositDenom := dep.Amount.Denom
|
remainingDebt := debt
|
||||||
for depositAmount.GTE(auctionSize) {
|
if !amountToAuction.IsPositive() {
|
||||||
// figure out how much debt is covered by one lots worth of collateral
|
return nil
|
||||||
depositDebtAmount := (sdk.NewDecFromInt(auctionSize).Quo(sdk.NewDecFromInt(totalCollateral))).Mul(sdk.NewDecFromInt(debt)).RoundInt()
|
}
|
||||||
penalty := k.ApplyLiquidationPenalty(ctx, depositDenom, depositDebtAmount)
|
for amountToAuction.GT(auctionSize) {
|
||||||
// start an auction for one lot, attempting to raise depositDebtAmount plus the liquidation penalty
|
debtCoveredByAuction := (sdk.NewDecFromInt(auctionSize).Quo(sdk.NewDecFromInt(totalCollateralAmount))).Mul(sdk.NewDecFromInt(debt)).RoundInt()
|
||||||
|
penalty := k.ApplyLiquidationPenalty(ctx, collateral.Denom, debtCoveredByAuction)
|
||||||
_, err := k.auctionKeeper.StartCollateralAuction(
|
_, err := k.auctionKeeper.StartCollateralAuction(
|
||||||
ctx, types.LiquidatorMacc, sdk.NewCoin(depositDenom, auctionSize), sdk.NewCoin(principalDenom, depositDebtAmount.Add(penalty)), []sdk.AccAddress{dep.Depositor},
|
ctx, types.LiquidatorMacc, sdk.NewCoin(collateral.Denom, auctionSize), sdk.NewCoin(principalDenom, debtCoveredByAuction.Add(penalty)), []sdk.AccAddress{returnAddr},
|
||||||
[]sdk.Int{auctionSize}, sdk.NewCoin(k.GetDebtDenom(ctx), depositDebtAmount))
|
[]sdk.Int{auctionSize}, sdk.NewCoin(k.GetDebtDenom(ctx), debtCoveredByAuction))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdk.ZeroInt(), sdk.ZeroInt(), err
|
return err
|
||||||
}
|
}
|
||||||
depositAmount = depositAmount.Sub(auctionSize)
|
amountToAuction = amountToAuction.Sub(auctionSize)
|
||||||
totalCollateral = totalCollateral.Sub(auctionSize)
|
remainingDebt = remainingDebt.Sub(debtCoveredByAuction)
|
||||||
debt = debt.Sub(depositDebtAmount)
|
|
||||||
// subtract one lot's worth of debt from the total debt covered by this deposit
|
|
||||||
debtChange = debtChange.Add(depositDebtAmount)
|
|
||||||
collateralChange = collateralChange.Add(auctionSize)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return debtChange, collateralChange, nil
|
penalty := k.ApplyLiquidationPenalty(ctx, collateral.Denom, remainingDebt)
|
||||||
}
|
_, err = k.auctionKeeper.StartCollateralAuction(
|
||||||
|
ctx, types.LiquidatorMacc, sdk.NewCoin(collateral.Denom, amountToAuction), sdk.NewCoin(principalDenom, remainingDebt.Add(penalty)), []sdk.AccAddress{returnAddr},
|
||||||
// CreateAuctionFromPartialDeposits creates an auction from the input partial deposits
|
[]sdk.Int{amountToAuction}, sdk.NewCoin(k.GetDebtDenom(ctx), remainingDebt))
|
||||||
func (k Keeper) CreateAuctionFromPartialDeposits(ctx sdk.Context, partialDeps partialDeposits, debt sdk.Int, collateral sdk.Int, auctionSize sdk.Int, bidDenom string) (debtChange, collateralChange sdk.Int, err error) {
|
|
||||||
|
|
||||||
returnAddrs := []sdk.AccAddress{}
|
|
||||||
returnWeights := []sdk.Int{}
|
|
||||||
depositDenom := partialDeps[0].Amount.Denom
|
|
||||||
for _, pd := range partialDeps {
|
|
||||||
returnAddrs = append(returnAddrs, pd.Depositor)
|
|
||||||
returnWeights = append(returnWeights, pd.DebtShare)
|
|
||||||
}
|
|
||||||
penalty := k.ApplyLiquidationPenalty(ctx, depositDenom, partialDeps.SumDebt())
|
|
||||||
_, err = k.auctionKeeper.StartCollateralAuction(ctx, types.LiquidatorMacc, sdk.NewCoin(partialDeps[0].Amount.Denom, auctionSize), sdk.NewCoin(bidDenom, partialDeps.SumDebt().Add(penalty)), returnAddrs, returnWeights, sdk.NewCoin(k.GetDebtDenom(ctx), partialDeps.SumDebt()))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdk.ZeroInt(), sdk.ZeroInt(), err
|
return err
|
||||||
}
|
}
|
||||||
debtChange = partialDeps.SumDebt()
|
|
||||||
collateralChange = partialDeps.SumCollateral()
|
return nil
|
||||||
return debtChange, collateralChange, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetSurplusAndDebt burns surplus and debt coins equal to the minimum of surplus and debt balances held by the liquidator module account
|
// NetSurplusAndDebt burns surplus and debt coins equal to the minimum of surplus and debt balances held by the liquidator module account
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user