Skip to content

Commit

Permalink
refactor!: new pool interface and remove old code
Browse files Browse the repository at this point in the history
  • Loading branch information
hallazzang committed Jun 9, 2022
1 parent e154e38 commit bc5a6f2
Show file tree
Hide file tree
Showing 11 changed files with 255 additions and 837 deletions.
114 changes: 57 additions & 57 deletions x/liquidity/amm/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,63 +28,63 @@ func (dir PriceDirection) String() string {
}
}

// FindMatchPrice returns the best match price for given order sources.
// If there is no matchable orders, found will be false.
func FindMatchPrice(os OrderSource, tickPrec int) (matchPrice sdk.Dec, found bool) {
highestBuyPrice, found := os.HighestBuyPrice()
if !found {
return sdk.Dec{}, false
}
lowestSellPrice, found := os.LowestSellPrice()
if !found {
return sdk.Dec{}, false
}
if highestBuyPrice.LT(lowestSellPrice) {
return sdk.Dec{}, false
}

prec := TickPrecision(tickPrec)
lowestTickIdx := prec.TickToIndex(prec.LowestTick())
highestTickIdx := prec.TickToIndex(prec.HighestTick())
var i, j int
i, found = findFirstTrueCondition(lowestTickIdx, highestTickIdx, func(i int) bool {
return os.BuyAmountOver(prec.TickFromIndex(i + 1)).LTE(os.SellAmountUnder(prec.TickFromIndex(i)))
})
if !found {
return sdk.Dec{}, false
}
j, found = findFirstTrueCondition(highestTickIdx, lowestTickIdx, func(i int) bool {
return os.BuyAmountOver(prec.TickFromIndex(i)).GTE(os.SellAmountUnder(prec.TickFromIndex(i - 1)))
})
if !found {
return sdk.Dec{}, false
}
midTick := TickFromIndex(i, tickPrec).Add(TickFromIndex(j, tickPrec)).QuoInt64(2)
return RoundPrice(midTick, tickPrec), true
}

// findFirstTrueCondition uses the binary search to find the first index
// where f(i) is true, while searching in range [start, end].
// It assumes that f(j) == false where j < i and f(j) == true where j >= i.
// start can be greater than end.
func findFirstTrueCondition(start, end int, f func(i int) bool) (i int, found bool) {
if start < end {
i = start + sort.Search(end-start+1, func(i int) bool {
return f(start + i)
})
if i > end {
return 0, false
}
return i, true
}
i = start - sort.Search(start-end+1, func(i int) bool {
return f(start - i)
})
if i < end {
return 0, false
}
return i, true
}
//// FindMatchPrice returns the best match price for given order sources.
//// If there is no matchable orders, found will be false.
//func FindMatchPrice(os OrderSource, tickPrec int) (matchPrice sdk.Dec, found bool) {
// highestBuyPrice, found := os.HighestBuyPrice()
// if !found {
// return sdk.Dec{}, false
// }
// lowestSellPrice, found := os.LowestSellPrice()
// if !found {
// return sdk.Dec{}, false
// }
// if highestBuyPrice.LT(lowestSellPrice) {
// return sdk.Dec{}, false
// }
//
// prec := TickPrecision(tickPrec)
// lowestTickIdx := prec.TickToIndex(prec.LowestTick())
// highestTickIdx := prec.TickToIndex(prec.HighestTick())
// var i, j int
// i, found = findFirstTrueCondition(lowestTickIdx, highestTickIdx, func(i int) bool {
// return os.BuyAmountOver(prec.TickFromIndex(i + 1)).LTE(os.SellAmountUnder(prec.TickFromIndex(i)))
// })
// if !found {
// return sdk.Dec{}, false
// }
// j, found = findFirstTrueCondition(highestTickIdx, lowestTickIdx, func(i int) bool {
// return os.BuyAmountOver(prec.TickFromIndex(i)).GTE(os.SellAmountUnder(prec.TickFromIndex(i - 1)))
// })
// if !found {
// return sdk.Dec{}, false
// }
// midTick := TickFromIndex(i, tickPrec).Add(TickFromIndex(j, tickPrec)).QuoInt64(2)
// return RoundPrice(midTick, tickPrec), true
//}
//
//// findFirstTrueCondition uses the binary search to find the first index
//// where f(i) is true, while searching in range [start, end].
//// It assumes that f(j) == false where j < i and f(j) == true where j >= i.
//// start can be greater than end.
//func findFirstTrueCondition(start, end int, f func(i int) bool) (i int, found bool) {
// if start < end {
// i = start + sort.Search(end-start+1, func(i int) bool {
// return f(start + i)
// })
// if i > end {
// return 0, false
// }
// return i, true
// }
// i = start - sort.Search(start-end+1, func(i int) bool {
// return f(start - i)
// })
// if i < end {
// return 0, false
// }
// return i, true
//}

func (ob *OrderBook) InstantMatch(ctx MatchContext, lastPrice sdk.Dec) (matched bool) {
buySums := make([]sdk.Int, 0, len(ob.buys.ticks))
Expand Down
6 changes: 1 addition & 5 deletions x/liquidity/amm/match_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,7 @@ func parseOrders(s string) []Order {
panic(fmt.Errorf("invalid batch id: %s", chunks[2]))
}
}
orders = append(orders, &UserOrder{
BaseOrder: *newOrder(dir, price, amt),
OrderId: 0,
BatchId: batchId,
})
orders = append(orders, NewUserOrder(0, batchId, dir, price, amt))
}
return orders
}
Expand Down
101 changes: 43 additions & 58 deletions x/liquidity/amm/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,30 +43,22 @@ type Order interface {
// HasPriority returns true if the order has higher priority
// than the other order.
HasPriority(other Order) bool
String() string
}

// BaseOrder is the base struct for an Order.
type BaseOrder struct {
Direction OrderDirection
Price sdk.Dec
Amount sdk.Int
OpenAmount sdk.Int
OfferCoin sdk.Coin
RemainingOfferCoin sdk.Coin
ReceivedDemandCoin sdk.Coin
Matched bool
Direction OrderDirection
Price sdk.Dec
Amount sdk.Int
}

// NewBaseOrder returns a new BaseOrder.
func NewBaseOrder(dir OrderDirection, price sdk.Dec, amt sdk.Int, offerCoin sdk.Coin, demandCoinDenom string) *BaseOrder {
func NewBaseOrder(dir OrderDirection, price sdk.Dec, amt sdk.Int) *BaseOrder {
return &BaseOrder{
Direction: dir,
Price: price,
Amount: amt,
OpenAmount: amt,
OfferCoin: offerCoin,
RemainingOfferCoin: offerCoin,
ReceivedDemandCoin: sdk.NewCoin(demandCoinDenom, sdk.ZeroInt()),
Direction: dir,
Price: price,
Amount: amt,
}
}

Expand Down Expand Up @@ -95,48 +87,8 @@ func (order *BaseOrder) HasPriority(other Order) bool {
return order.Amount.GT(other.GetAmount())
}

// GetOpenAmount returns open(not matched) amount of the order.
func (order *BaseOrder) GetOpenAmount() sdk.Int {
return order.OpenAmount
}

// SetOpenAmount sets open amount of the order.
func (order *BaseOrder) SetOpenAmount(amt sdk.Int) {
order.OpenAmount = amt
}

func (order *BaseOrder) GetOfferCoin() sdk.Coin {
return order.OfferCoin
}

// GetRemainingOfferCoin returns remaining offer coin of the order.
func (order *BaseOrder) GetRemainingOfferCoin() sdk.Coin {
return order.RemainingOfferCoin
}

// DecrRemainingOfferCoin decrements remaining offer coin amount of the order.
func (order *BaseOrder) DecrRemainingOfferCoin(amt sdk.Int) {
order.RemainingOfferCoin = order.RemainingOfferCoin.SubAmount(amt)
}

// GetReceivedDemandCoin returns received demand coin of the order.
func (order *BaseOrder) GetReceivedDemandCoin() sdk.Coin {
return order.ReceivedDemandCoin
}

// IncrReceivedDemandCoin increments received demand coin amount of the order.
func (order *BaseOrder) IncrReceivedDemandCoin(amt sdk.Int) {
order.ReceivedDemandCoin = order.ReceivedDemandCoin.AddAmount(amt)
}

// IsMatched returns whether the order is matched or not.
func (order *BaseOrder) IsMatched() bool {
return order.Matched
}

// SetMatched sets whether the order is matched or not.
func (order *BaseOrder) SetMatched(matched bool) {
order.Matched = matched
func (order *BaseOrder) String() string {
return fmt.Sprintf("BaseOrder(%s,%s,%s)", order.Direction, order.Price, order.Amount)
}

type UserOrder struct {
Expand All @@ -145,6 +97,18 @@ type UserOrder struct {
BatchId uint64
}

func NewUserOrder(orderId, batchId uint64, dir OrderDirection, price sdk.Dec, amt sdk.Int) *UserOrder {
return &UserOrder{
BaseOrder: BaseOrder{
Direction: dir,
Price: price,
Amount: amt,
},
OrderId: orderId,
BatchId: batchId,
}
}

func (order *UserOrder) GetBatchId() uint64 {
return order.BatchId
}
Expand All @@ -163,11 +127,27 @@ func (order *UserOrder) HasPriority(other Order) bool {
}
}

func (order *UserOrder) String() string {
return fmt.Sprintf("UserOrder(%d,%d,%s,%s,%s)",
order.OrderId, order.BatchId, order.Direction, order.Price, order.Amount)
}

type PoolOrder struct {
BaseOrder
PoolId uint64
}

func NewPoolOrder(poolId uint64, dir OrderDirection, price sdk.Dec, amt sdk.Int) *PoolOrder {
return &PoolOrder{
BaseOrder: BaseOrder{
Direction: dir,
Price: price,
Amount: amt,
},
PoolId: poolId,
}
}

func (order *PoolOrder) HasPriority(other Order) bool {
if !order.Amount.Equal(other.GetAmount()) {
return order.Amount.GT(other.GetAmount())
Expand All @@ -182,6 +162,11 @@ func (order *PoolOrder) HasPriority(other Order) bool {
}
}

func (order *PoolOrder) String() string {
return fmt.Sprintf("PoolOrder(%d,%s,%s,%s)",
order.PoolId, order.Direction, order.Price, order.Amount)
}

func TotalAmount(orders []Order) sdk.Int {
amt := sdk.ZeroInt()
for _, order := range orders {
Expand Down
18 changes: 0 additions & 18 deletions x/liquidity/amm/orderbook.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@ func (ob *OrderBook) AddOrder(orders ...Order) {
}
}

// OrdersAt returns orders at given price in the order book.
// Note that the orders are not sorted.
func (ob *OrderBook) OrdersAt(price sdk.Dec) []Order {
return append(ob.BuyOrdersAt(price), ob.SellOrdersAt(price)...)
}

// BuyOrdersAt returns buy orders at given price in the order book.
// Note that the orders are not sorted.
func (ob *OrderBook) BuyOrdersAt(price sdk.Dec) []Order {
Expand All @@ -53,18 +47,6 @@ func (ob *OrderBook) SellOrdersAt(price sdk.Dec) []Order {
return ob.sells.ordersAt(price)
}

// HighestBuyPrice returns the highest buy price in the order book.
func (ob *OrderBook) HighestBuyPrice() (sdk.Dec, bool) {
price, _, found := ob.buys.highestPrice()
return price, found
}

// LowestSellPrice returns the lowest sell price in the order book.
func (ob *OrderBook) LowestSellPrice() (sdk.Dec, bool) {
price, _, found := ob.sells.lowestPrice()
return price, found
}

func (ob *OrderBook) HighestPrice() (sdk.Dec, bool) {
highestBuyPrice, _, foundBuy := ob.buys.highestPrice()
highestSellPrice, _, foundSell := ob.sells.highestPrice()
Expand Down
14 changes: 1 addition & 13 deletions x/liquidity/amm/orderbook_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,6 @@ import (
utils "github.com/cosmosquad-labs/squad/types"
)

// Copied from orderbook_test.go
func newOrder(dir OrderDirection, price sdk.Dec, amt sdk.Int) *BaseOrder {
var offerCoinDenom, demandCoinDenom string
switch dir {
case Buy:
offerCoinDenom, demandCoinDenom = "denom2", "denom1"
case Sell:
offerCoinDenom, demandCoinDenom = "denom1", "denom2"
}
return NewBaseOrder(dir, price, amt, sdk.NewCoin(offerCoinDenom, OfferCoinAmount(dir, price, amt)), demandCoinDenom)
}

func TestOrderBookTicks_add(t *testing.T) {
prices := []sdk.Dec{
utils.ParseDec("1.0"),
Expand All @@ -35,7 +23,7 @@ func TestOrderBookTicks_add(t *testing.T) {
}
var ticks orderBookTicks
for _, price := range prices {
ticks.addOrder(newOrder(Buy, price, sdk.NewInt(10000)))
ticks.addOrder(NewBaseOrder(Buy, price, sdk.NewInt(10000)))
}
pricesSet := map[string]struct{}{}
for _, price := range prices {
Expand Down
Loading

0 comments on commit bc5a6f2

Please sign in to comment.