-
Notifications
You must be signed in to change notification settings - Fork 3
/
order.go
106 lines (95 loc) · 2.91 KB
/
order.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package types
import (
"fmt"
"sort"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmosquad-labs/squad/x/liquidity/amm"
)
var (
_ amm.Order = (*UserOrder)(nil)
_ amm.Order = (*PoolOrder)(nil)
// PriceDescending defines a price comparator which is used to sort orders
// by price in descending order.
PriceDescending PriceComparator = func(a, b amm.Order) bool {
return a.GetPrice().GT(b.GetPrice())
}
// PriceAscending defines a price comparator which is used to sort orders
// by price in ascending order.
PriceAscending PriceComparator = func(a, b amm.Order) bool {
return a.GetPrice().LT(b.GetPrice())
}
)
// PriceComparator is used to sort orders by price.
type PriceComparator func(a, b amm.Order) bool
// SortOrders sorts orders by these four criteria:
// 1. Price - descending/ascending based on PriceComparator
// 2. Amount - Larger amount takes higher priority than smaller amount
// 3. Order type - pool orders take higher priority than user orders
// 4. Time - early orders take higher priority. For pools, the pool with
// lower pool id takes higher priority
func SortOrders(orders []amm.Order, cmp PriceComparator) {
sort.SliceStable(orders, func(i, j int) bool {
switch orderA := orders[i].(type) {
case *UserOrder:
switch orderB := orders[j].(type) {
case *UserOrder:
return orderA.RequestId < orderB.RequestId
case *PoolOrder:
return false
}
case *PoolOrder:
switch orderB := orders[j].(type) {
case *UserOrder:
return true
case *PoolOrder:
return orderA.PoolId < orderB.PoolId
}
}
panic(fmt.Sprintf("unknown order types: (%T, %T)", orders[i], orders[j]))
})
sort.SliceStable(orders, func(i, j int) bool {
return orders[i].GetAmount().GT(orders[j].GetAmount())
})
sort.SliceStable(orders, func(i, j int) bool {
return cmp(orders[i], orders[j])
})
}
// UserOrder is the user order type.
type UserOrder struct {
*amm.BaseOrder
RequestId uint64
Orderer sdk.AccAddress
}
// NewUserOrder returns a new user order.
func NewUserOrder(order Order) *UserOrder {
var dir amm.OrderDirection
switch order.Direction {
case OrderDirectionBuy:
dir = amm.Buy
case OrderDirectionSell:
dir = amm.Sell
}
return &UserOrder{
BaseOrder: amm.NewBaseOrder(dir, order.Price, order.OpenAmount, order.RemainingOfferCoin, order.ReceivedCoin.Denom),
RequestId: order.Id,
Orderer: order.GetOrderer(),
}
}
// PoolOrder is the pool order type.
type PoolOrder struct {
*amm.BaseOrder
PoolId uint64
ReserveAddress sdk.AccAddress
OfferCoin sdk.Coin
}
// NewPoolOrder returns a new pool order.
func NewPoolOrder(
poolId uint64, reserveAddr sdk.AccAddress, dir amm.OrderDirection, price sdk.Dec, amt sdk.Int,
offerCoin sdk.Coin, demandCoinDenom string) *PoolOrder {
return &PoolOrder{
BaseOrder: amm.NewBaseOrder(dir, price, amt, offerCoin, demandCoinDenom),
PoolId: poolId,
ReserveAddress: reserveAddr,
OfferCoin: offerCoin,
}
}