return false
}
- orders := e.peekOrders(tradePairs)
+ orders := e.orderBook.PeekOrders(tradePairs)
if len(orders) == 0 {
return false
}
- return isMatched(orders)
+ return IsMatched(orders)
}
// NextMatchedTx return the next matchable transaction by the specified trade pairs
return nil, errors.New("the specified trade pairs can not be matched")
}
- tx, err := e.buildMatchTx(e.peekOrders(tradePairs))
+ tx, err := e.buildMatchTx(sortOrders(e.orderBook.PeekOrders(tradePairs)))
if err != nil {
return nil, err
}
return types.NewTx(*txData), nil
}
-func (e *Engine) peekOrders(tradePairs []*common.TradePair) []*common.Order {
- var orders []*common.Order
- for _, tradePair := range tradePairs {
- order := e.orderBook.PeekOrder(tradePair)
- if order == nil {
- return nil
- }
-
- orders = append(orders, order)
- }
- return orders
-}
-
// MatchedTxFee is object to record the mov tx's fee information
type MatchedTxFee struct {
MaxFeeAmount int64
return (selfIdx + 1) % size
}
-func isMatched(orders []*common.Order) bool {
- rate := orders[0].Rate
- oppositeRate := 1.0
- for i := 1; i < len(orders); i++ {
- oppositeRate *= orders[i].Rate
+func IsMatched(orders []*common.Order) bool {
+ sortedOrders := sortOrders(orders)
+ if len(sortedOrders) == 0 {
+ return false
+ }
+
+ rate := orderRatio(sortedOrders[0])
+ oppositeRate := big.NewFloat(0).SetInt64(1)
+ for i := 1; i < len(sortedOrders); i++ {
+ oppositeRate.Mul(oppositeRate, orderRatio(sortedOrders[i]))
}
- return 1/rate >= oppositeRate
+
+ one := big.NewFloat(0).SetInt64(1)
+ return one.Quo(one, rate).Cmp(oppositeRate) >= 0
+}
+
+func orderRatio(order *common.Order) *big.Float {
+ ratio := big.NewFloat(0).SetInt64(order.RatioNumerator)
+ ratio.Quo(ratio, big.NewFloat(0).SetInt64(order.RatioDenominator))
+ return ratio
}
func setMatchTxArguments(txInput *types.TxInput, isPartialTrade bool, position int, receiveAmounts uint64) {
return errors.New("size of trade pairs at least 2")
}
- for i, tradePair := range tradePairs {
+ assetMap := make(map[string]bool)
+ for _, tradePair := range tradePairs {
+ assetMap[tradePair.FromAssetID.String()] = true
if *tradePair.FromAssetID == *tradePair.ToAssetID {
return errors.New("from asset id can't equal to asset id")
}
+ }
- oppositeTradePair := tradePairs[calcOppositeIndex(len(tradePairs), i)]
- if *tradePair.ToAssetID != *oppositeTradePair.FromAssetID {
- return errors.New("specified trade pairs is invalid")
+ for _, tradePair := range tradePairs {
+ key := tradePair.ToAssetID.String()
+ if _, ok := assetMap[key]; !ok {
+ return errors.New("invalid trade pairs")
}
+ delete(assetMap, key)
}
return nil
}
+
+func sortOrders(orders []*common.Order) []*common.Order {
+ orderMap := make(map[bc.AssetID]*common.Order)
+ firstOrder := orders[0]
+ for i := 1; i < len(orders); i++ {
+ orderMap[*orders[i].FromAssetID] = orders[i]
+ }
+
+ sortedOrders := []*common.Order{firstOrder}
+ for order := firstOrder; *order.ToAssetID != *firstOrder.FromAssetID; {
+ nextOrder, ok := orderMap[*order.ToAssetID]
+ if !ok {
+ return nil
+ }
+
+ sortedOrders = append(sortedOrders, nextOrder)
+ order = nextOrder
+ }
+ return sortedOrders
+}