mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-11-10 18:15:19 +00:00
ffef832d45
- Upgrade cosmos-sdk to v0.44.5 from v0.39.2 - Add Legacy Tx Endpoint for backwards compatibility - Add IBC v1.2.3 Support Co-authored-by: DracoLi <draco@dracoli.com> Co-authored-by: drklee3 <derrick@dlee.dev> Co-authored-by: denalimarsh <denalimarsh@gmail.com> Co-authored-by: Draco Li <draco@kava.io> Co-authored-by: Nick DeLuca <nickdeluca08@gmail.com> Co-authored-by: Kevin Davis <karzak@users.noreply.github.com> Co-authored-by: Denali Marsh <denali@kava.io>
261 lines
9.8 KiB
Go
261 lines
9.8 KiB
Go
package v0_15
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
v40auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v040"
|
|
)
|
|
|
|
const (
|
|
CollateralAuctionType = "collateral"
|
|
SurplusAuctionType = "surplus"
|
|
DebtAuctionType = "debt"
|
|
ForwardAuctionPhase = "forward"
|
|
ReverseAuctionPhase = "reverse"
|
|
)
|
|
|
|
// Auction is an interface for handling common actions on auctions.
|
|
type Auction interface {
|
|
GetID() uint64
|
|
WithID(uint64) Auction
|
|
|
|
GetInitiator() string
|
|
GetLot() sdk.Coin
|
|
GetBidder() sdk.AccAddress
|
|
GetBid() sdk.Coin
|
|
GetEndTime() time.Time
|
|
GetHasReceivedBids() bool
|
|
GetMaxEndTime() time.Time
|
|
|
|
GetType() string
|
|
GetPhase() string
|
|
}
|
|
|
|
var (
|
|
_ Auction = &SurplusAuction{}
|
|
_ GenesisAuction = &SurplusAuction{}
|
|
_ Auction = &DebtAuction{}
|
|
_ GenesisAuction = &DebtAuction{}
|
|
_ Auction = &CollateralAuction{}
|
|
_ GenesisAuction = &CollateralAuction{}
|
|
)
|
|
|
|
// BaseAuction is a common type shared by all Auctions.
|
|
type BaseAuction struct {
|
|
ID uint64 `json:"id" yaml:"id"`
|
|
Initiator string `json:"initiator" yaml:"initiator"` // Module name that starts the auction. Pays out Lot.
|
|
Lot sdk.Coin `json:"lot" yaml:"lot"` // Coins that will paid out by Initiator to the winning bidder.
|
|
Bidder sdk.AccAddress `json:"bidder" yaml:"bidder"` // Latest bidder. Receiver of Lot.
|
|
Bid sdk.Coin `json:"bid" yaml:"bid"` // Coins paid into the auction the bidder.
|
|
HasReceivedBids bool `json:"has_received_bids" yaml:"has_received_bids"` // Whether the auction has received any bids or not.
|
|
EndTime time.Time `json:"end_time" yaml:"end_time"` // Current auction closing time. Triggers at the end of the block with time ≥ EndTime.
|
|
MaxEndTime time.Time `json:"max_end_time" yaml:"max_end_time"` // Maximum closing time. Auctions can close before this but never after.
|
|
}
|
|
|
|
// GetID is a getter for auction ID.
|
|
func (a BaseAuction) GetID() uint64 { return a.ID }
|
|
|
|
// GetInitiator is a getter for auction Initiator.
|
|
func (a BaseAuction) GetInitiator() string { return a.Initiator }
|
|
|
|
// GetLot is a getter for auction Lot.
|
|
func (a BaseAuction) GetLot() sdk.Coin { return a.Lot }
|
|
|
|
// GetBidder is a getter for auction Bidder.
|
|
func (a BaseAuction) GetBidder() sdk.AccAddress { return a.Bidder }
|
|
|
|
// GetBid is a getter for auction Bid.
|
|
func (a BaseAuction) GetBid() sdk.Coin { return a.Bid }
|
|
|
|
// GetEndTime is a getter for auction end time.
|
|
func (a BaseAuction) GetEndTime() time.Time { return a.EndTime }
|
|
|
|
// GetType returns the auction type. Used to identify auctions in event attributes.
|
|
func (a BaseAuction) GetType() string { return "base" }
|
|
|
|
// GetMaxEndTime is a getter for MaxEndTime
|
|
func (a BaseAuction) GetMaxEndTime() time.Time { return a.MaxEndTime }
|
|
|
|
// GetMaxEndTime is a getter for GetHasReceivedBids
|
|
func (a BaseAuction) GetHasReceivedBids() bool { return a.HasReceivedBids }
|
|
|
|
// Validate verifies that the auction end time is before max end time
|
|
func (a BaseAuction) Validate() error {
|
|
// ID can be 0 for surplus, debt and collateral auctions
|
|
if strings.TrimSpace(a.Initiator) == "" {
|
|
return errors.New("auction initiator cannot be blank")
|
|
}
|
|
if !a.Lot.IsValid() {
|
|
return fmt.Errorf("invalid lot: %s", a.Lot)
|
|
}
|
|
// NOTE: bidder can be empty for Surplus and Collateral auctions
|
|
if !a.Bidder.Empty() && len(a.Bidder) != v40auth.AddrLen {
|
|
return fmt.Errorf("the expected bidder address length is %d, actual length is %d", v40auth.AddrLen, len(a.Bidder))
|
|
}
|
|
if !a.Bid.IsValid() {
|
|
return fmt.Errorf("invalid bid: %s", a.Bid)
|
|
}
|
|
if a.EndTime.Unix() <= 0 || a.MaxEndTime.Unix() <= 0 {
|
|
return errors.New("end time cannot be zero")
|
|
}
|
|
if a.EndTime.After(a.MaxEndTime) {
|
|
return fmt.Errorf("MaxEndTime < EndTime (%s < %s)", a.MaxEndTime, a.EndTime)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 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.
|
|
type DebtAuction struct {
|
|
BaseAuction `json:"base_auction" yaml:"base_auction"`
|
|
|
|
CorrespondingDebt sdk.Coin `json:"corresponding_debt" yaml:"corresponding_debt"`
|
|
}
|
|
|
|
// WithID returns an auction with the ID set.
|
|
func (a DebtAuction) WithID(id uint64) Auction { a.ID = id; return a }
|
|
|
|
// GetType returns the auction type. Used to identify auctions in event attributes.
|
|
func (a DebtAuction) GetType() string { return DebtAuctionType }
|
|
|
|
// GetModuleAccountCoins returns the total number of coins held in the module account for this auction.
|
|
// It is used in genesis initialize the module account correctly.
|
|
func (a DebtAuction) GetModuleAccountCoins() sdk.Coins {
|
|
// a.Lot is minted at auction close, so is never stored in the module account
|
|
// a.Bid is paid out on bids, so is never stored in the module account
|
|
return sdk.NewCoins(a.CorrespondingDebt)
|
|
}
|
|
|
|
// GetPhase returns the direction of a debt auction, which never changes.
|
|
func (a DebtAuction) GetPhase() string { return ReverseAuctionPhase }
|
|
|
|
// Validate validates the DebtAuction fields values.
|
|
func (a DebtAuction) Validate() error {
|
|
if !a.CorrespondingDebt.IsValid() {
|
|
return fmt.Errorf("invalid corresponding debt: %s", a.CorrespondingDebt)
|
|
}
|
|
return a.BaseAuction.Validate()
|
|
}
|
|
|
|
// 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.
|
|
type SurplusAuction struct {
|
|
BaseAuction `json:"base_auction" yaml:"base_auction"`
|
|
}
|
|
|
|
// WithID returns an auction with the ID set.
|
|
func (a SurplusAuction) WithID(id uint64) Auction { a.ID = id; return a }
|
|
|
|
// GetType returns the auction type. Used to identify auctions in event attributes.
|
|
func (a SurplusAuction) GetType() string { return SurplusAuctionType }
|
|
|
|
// GetModuleAccountCoins returns the total number of coins held in the module account for this auction.
|
|
// It is used in genesis initialize the module account correctly.
|
|
func (a SurplusAuction) GetModuleAccountCoins() sdk.Coins {
|
|
// a.Bid is paid out on bids, so is never stored in the module account
|
|
return sdk.NewCoins(a.Lot)
|
|
}
|
|
|
|
// GetPhase returns the direction of a surplus auction, which never changes.
|
|
func (a SurplusAuction) GetPhase() string { return ForwardAuctionPhase }
|
|
|
|
// CollateralAuction is a two phase auction.
|
|
// Initially, in forward auction phase, bids can be placed up to a max bid.
|
|
// Then it switches to a reverse auction phase, where the initial amount up for auction is bid down.
|
|
// 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.
|
|
type CollateralAuction struct {
|
|
BaseAuction `json:"base_auction" yaml:"base_auction"`
|
|
|
|
CorrespondingDebt sdk.Coin `json:"corresponding_debt" yaml:"corresponding_debt"`
|
|
MaxBid sdk.Coin `json:"max_bid" yaml:"max_bid"`
|
|
LotReturns WeightedAddresses `json:"lot_returns" yaml:"lot_returns"`
|
|
}
|
|
|
|
// WithID returns an auction with the ID set.
|
|
func (a CollateralAuction) WithID(id uint64) Auction { a.ID = id; return a }
|
|
|
|
// GetType returns the auction type. Used to identify auctions in event attributes.
|
|
func (a CollateralAuction) GetType() string { return CollateralAuctionType }
|
|
|
|
// GetModuleAccountCoins returns the total number of coins held in the module account for this auction.
|
|
// It is used in genesis initialize the module account correctly.
|
|
func (a CollateralAuction) GetModuleAccountCoins() sdk.Coins {
|
|
// a.Bid is paid out on bids, so is never stored in the module account
|
|
return sdk.NewCoins(a.Lot).Add(sdk.NewCoins(a.CorrespondingDebt)...)
|
|
}
|
|
|
|
// IsReversePhase returns whether the auction has switched over to reverse phase or not.
|
|
// CollateralAuctions initially start in forward phase.
|
|
func (a CollateralAuction) IsReversePhase() bool {
|
|
return a.Bid.IsEqual(a.MaxBid)
|
|
}
|
|
|
|
// GetPhase returns the direction of a collateral auction.
|
|
func (a CollateralAuction) GetPhase() string {
|
|
if a.IsReversePhase() {
|
|
return ReverseAuctionPhase
|
|
}
|
|
return ForwardAuctionPhase
|
|
}
|
|
|
|
// GetLotReturns returns a collateral auction's lot owners
|
|
func (a CollateralAuction) GetLotReturns() WeightedAddresses {
|
|
return a.LotReturns
|
|
}
|
|
|
|
// Validate validates the CollateralAuction fields values.
|
|
func (a CollateralAuction) Validate() error {
|
|
if !a.CorrespondingDebt.IsValid() {
|
|
return fmt.Errorf("invalid corresponding debt: %s", a.CorrespondingDebt)
|
|
}
|
|
if !a.MaxBid.IsValid() {
|
|
return fmt.Errorf("invalid max bid: %s", a.MaxBid)
|
|
}
|
|
if err := a.LotReturns.Validate(); err != nil {
|
|
return fmt.Errorf("invalid lot returns: %w", err)
|
|
}
|
|
return a.BaseAuction.Validate()
|
|
}
|
|
|
|
// WeightedAddresses is a type for storing some addresses and associated weights.
|
|
type WeightedAddresses struct {
|
|
Addresses []sdk.AccAddress `json:"addresses" yaml:"addresses"`
|
|
Weights []sdk.Int `json:"weights" yaml:"weights"`
|
|
}
|
|
|
|
// Validate checks for that the weights are not negative, not all zero, and the lengths match.
|
|
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) {
|
|
return fmt.Errorf("number of addresses doesn't match number of weights, %d ≠ %d", len(wa.Addresses), len(wa.Weights))
|
|
}
|
|
|
|
totalWeight := sdk.ZeroInt()
|
|
for i := range wa.Addresses {
|
|
if wa.Addresses[i].Empty() {
|
|
return fmt.Errorf("address %d cannot be empty", i)
|
|
}
|
|
if len(wa.Addresses[i]) != v40auth.AddrLen {
|
|
return fmt.Errorf("address %d has an invalid length: expected %d, got %d", i, v40auth.AddrLen, len(wa.Addresses[i]))
|
|
}
|
|
if wa.Weights[i].IsNegative() {
|
|
return fmt.Errorf("weight %d contains a negative amount: %s", i, wa.Weights[i])
|
|
}
|
|
totalWeight = totalWeight.Add(wa.Weights[i])
|
|
}
|
|
|
|
if !totalWeight.IsPositive() {
|
|
return fmt.Errorf("total weight must be positive")
|
|
}
|
|
|
|
return nil
|
|
}
|