func (a *ForwardReverseAuction) PlaceBid(currentBlockHeight endTime, bidder sdk.AccAddress, lot sdk.Coin, bid sdk.Coin) (outputs []bankOutput, inputs []bankInput, err sdk.Error) {
	if currentBlockHeight > a.EndTime {
		return []bankOutput{}, []bankInput{}, sdk.ErrInternal("auction has closed")
	}
	switch {
	case a.Bid.IsLT(a.MaxBid) && bid.IsLT(a.MaxBid):
		if !a.Bid.IsLT(bid) {  
			return []bankOutput{}, []bankInput{}, sdk.ErrInternal("bid not greater than last bid")
		}
		outputs = []bankOutput{{bidder, bid}}                                   
		inputs = []bankInput{{a.Bidder, a.Bid}, {a.Initiator, bid.Sub(a.Bid)}}  
	case a.Bid.IsLT(a.MaxBid):
		if !bid.IsEqual(a.MaxBid) {  
			return []bankOutput{}, []bankInput{}, sdk.ErrInternal("bid greater than the max bid")
		}
		outputs = []bankOutput{{bidder, bid}}  
		inputs = []bankInput{
			{a.Bidder, a.Bid},                
			{a.Initiator, bid.Sub(a.Bid)},    
			{a.OtherPerson, a.Lot.Sub(lot)},  
		}
	case a.Bid.IsEqual(a.MaxBid):
		if !lot.IsLT(a.Lot) {  
			return []bankOutput{}, []bankInput{}, sdk.ErrInternal("lot not smaller than last lot")
		}
		outputs = []bankOutput{{bidder, a.Bid}}                                   
		inputs = []bankInput{{a.Bidder, a.Bid}, {a.OtherPerson, a.Lot.Sub(lot)}}  
	default:
		panic("should never be reached")  
	}
	a.Bidder = bidder
	a.Lot = lot
	a.Bid = bid
	a.EndTime = endTime(min(int64(currentBlockHeight+BidDuration), int64(a.MaxEndTime)))  
	return outputs, inputs, nil
}
PlaceBid implements auction
package auction
import (
	"fmt"
	"strconv"
	sdk "github.com/cosmos/cosmos-sdk/types"
)
const (
	MaxAuctionDuration endTime = 2 * 24 * 3600 / 5  
	BidDuration endTime = 3 * 3600 / 5  
)
type Auction interface {
	GetID() ID
	SetID(ID)
	PlaceBid(currentBlockHeight endTime, bidder sdk.AccAddress, lot sdk.Coin, bid sdk.Coin) ([]bankOutput, []bankInput, sdk.Error)
	GetEndTime() endTime  
	GetPayout() bankInput
	String() string
}
type BaseAuction struct {
	ID         ID
	Initiator  sdk.AccAddress  
	Lot        sdk.Coin        
	Bidder     sdk.AccAddress  
	Bid        sdk.Coin        
	EndTime    endTime         
	MaxEndTime endTime         
}
type ID uint64
func NewIDFromString(s string) (ID, error) {
	n, err := strconv.ParseUint(s, 10, 64)  
	if err != nil {
		return 0, err
	}
	return ID(n), nil
}
type endTime int64  
type bankInput struct {
	Address sdk.AccAddress
	Coin    sdk.Coin
}
type bankOutput struct {
	Address sdk.AccAddress
	Coin    sdk.Coin
}
func (a BaseAuction) GetID() ID { return a.ID }
func (a *BaseAuction) SetID(id ID) { a.ID = id }
func (a BaseAuction) GetEndTime() endTime { return a.EndTime }
func (a BaseAuction) GetPayout() bankInput {
	return bankInput{a.Bidder, a.Lot}
}
func (e endTime) String() string {
	return string(e)
}
func (a BaseAuction) String() string {
	return fmt.Sprintf(`Auction %d:
  Initiator:              %s
  Lot:               			%s
  Bidder:            		  %s
  Bid:        						%s
  End Time:   						%s
  Max End Time:      			%s`,
		a.GetID(), a.Initiator, a.Lot,
		a.Bidder, a.Bid, a.GetEndTime().String(),
		a.MaxEndTime.String(),
	)
}
type ForwardAuction struct {
	BaseAuction
}
func NewForwardAuction(seller sdk.AccAddress, lot sdk.Coin, initialBid sdk.Coin, endTime endTime) (ForwardAuction, bankOutput) {
	auction := ForwardAuction{BaseAuction{
		Initiator:  seller,
		Lot:        lot,
		Bidder:     seller,      
		Bid:        initialBid,  
		EndTime:    endTime,
		MaxEndTime: endTime,
	}}
	output := bankOutput{seller, lot}
	return auction, output
}
func (a *ForwardAuction) PlaceBid(currentBlockHeight endTime, bidder sdk.AccAddress, lot sdk.Coin, bid sdk.Coin) ([]bankOutput, []bankInput, sdk.Error) {
	if currentBlockHeight > a.EndTime {
		return []bankOutput{}, []bankInput{}, sdk.ErrInternal("auction has closed")
	}
	if !a.Bid.IsLT(bid) {  
		return []bankOutput{}, []bankInput{}, sdk.ErrInternal("bid not greater than last bid")
	}
	outputs := []bankOutput{{bidder, bid}}                                   
	inputs := []bankInput{{a.Bidder, a.Bid}, {a.Initiator, bid.Sub(a.Bid)}}  
	a.Bidder = bidder
	a.Bid = bid
	a.EndTime = endTime(min(int64(currentBlockHeight+BidDuration), int64(a.MaxEndTime)))  
	return outputs, inputs, nil
}
type ReverseAuction struct {
	BaseAuction
}
func NewReverseAuction(buyer sdk.AccAddress, bid sdk.Coin, initialLot sdk.Coin, endTime endTime) (ReverseAuction, bankOutput) {
	auction := ReverseAuction{BaseAuction{
		Initiator:  buyer,
		Lot:        initialLot,
		Bidder:     buyer,  
		Bid:        bid,    
		EndTime:    endTime,
		MaxEndTime: endTime,
	}}
	output := bankOutput{buyer, initialLot}
	return auction, output
}
func (a *ReverseAuction) PlaceBid(currentBlockHeight endTime, bidder sdk.AccAddress, lot sdk.Coin, bid sdk.Coin) ([]bankOutput, []bankInput, sdk.Error) {
	if currentBlockHeight > a.EndTime {
		return []bankOutput{}, []bankInput{}, sdk.ErrInternal("auction has closed")
	}
	if !lot.IsLT(a.Lot) {  
		return []bankOutput{}, []bankInput{}, sdk.ErrInternal("lot not smaller than last lot")
	}
	outputs := []bankOutput{{bidder, a.Bid}}                                 
	inputs := []bankInput{{a.Bidder, a.Bid}, {a.Initiator, a.Lot.Sub(lot)}}  
	a.Bidder = bidder
	a.Lot = lot
	a.EndTime = endTime(min(int64(currentBlockHeight+BidDuration), int64(a.MaxEndTime)))  
	return outputs, inputs, nil
}
type ForwardReverseAuction struct {
	BaseAuction
	MaxBid      sdk.Coin
	OtherPerson sdk.AccAddress  
}
func (a ForwardReverseAuction) String() string {
	return fmt.Sprintf(`Auction %d:
  Initiator:              %s
  Lot:               			%s
  Bidder:            		  %s
  Bid:        						%s
  End Time:   						%s
	Max End Time:      			%s
	Max Bid									%s
	Other Person						%s`,
		a.GetID(), a.Initiator, a.Lot,
		a.Bidder, a.Bid, a.GetEndTime().String(),
		a.MaxEndTime.String(), a.MaxBid, a.OtherPerson,
	)
}
func NewForwardReverseAuction(seller sdk.AccAddress, lot sdk.Coin, initialBid sdk.Coin, endTime endTime, maxBid sdk.Coin, otherPerson sdk.AccAddress) (ForwardReverseAuction, bankOutput) {
	auction := ForwardReverseAuction{
		BaseAuction: BaseAuction{
			Initiator:  seller,
			Lot:        lot,
			Bidder:     seller,      
			Bid:        initialBid,  
			EndTime:    endTime,
			MaxEndTime: endTime},
		MaxBid:      maxBid,
		OtherPerson: otherPerson,
	}
	output := bankOutput{seller, lot}
	return auction, output
}