OSDN Git Service

fix decimal (#479)
[bytom/vapor.git] / application / mov / match / match_test.go
index ee38a0a..7d013ec 100644 (file)
@@ -3,182 +3,87 @@ package match
 import (
        "testing"
 
-       "github.com/vapor/protocol/vm"
-       "github.com/vapor/testutil"
-
-       "github.com/vapor/application/mov/common"
-       "github.com/vapor/application/mov/database"
-       "github.com/vapor/protocol/bc"
-       "github.com/vapor/protocol/bc/types"
-       "github.com/vapor/protocol/vm/vmutil"
+       "github.com/bytom/vapor/application/mov/common"
+       "github.com/bytom/vapor/application/mov/mock"
+       "github.com/bytom/vapor/protocol/bc"
+       "github.com/bytom/vapor/protocol/bc/types"
+       "github.com/bytom/vapor/protocol/validation"
+       "github.com/bytom/vapor/testutil"
 )
 
-var (
-       btc = bc.NewAssetID([32]byte{1})
-       eth = bc.NewAssetID([32]byte{2})
+func TestGenerateMatchedTxs(t *testing.T) {
+       btc2eth := &common.TradePair{FromAssetID: &mock.BTC, ToAssetID: &mock.ETH}
+       eth2btc := &common.TradePair{FromAssetID: &mock.ETH, ToAssetID: &mock.BTC}
+       eth2eos := &common.TradePair{FromAssetID: &mock.ETH, ToAssetID: &mock.EOS}
+       eos2btc := &common.TradePair{FromAssetID: &mock.EOS, ToAssetID: &mock.BTC}
 
-       orders = []*common.Order{
-               // btc -> eth
-               {
-                       FromAssetID: &btc,
-                       ToAssetID:   &eth,
-                       Rate:        50,
-                       Utxo: &common.MovUtxo{
-                               SourceID:       hashPtr(testutil.MustDecodeHash("37b8edf656e45a7addf47f5626e114a8c394d918a36f61b5a2905675a09b40ae")),
-                               SourcePos:      0,
-                               Amount:         10,
-                               ControlProgram: mustCreateP2WMCProgram(eth, testutil.MustDecodeHexString("51"), 50, 1),
-                       },
-               },
+       cases := []struct {
+               desc            string
+               tradePairs      []*common.TradePair
+               initStoreOrders []*common.Order
+               wantMatchedTxs  []*types.Tx
+       }{
                {
-                       FromAssetID: &btc,
-                       ToAssetID:   &eth,
-                       Rate:        53,
-                       Utxo: &common.MovUtxo{
-                               SourceID:       hashPtr(testutil.MustDecodeHash("3ec2bbfb499a8736d377b547eee5392bcddf7ec2b287e9ed20b5938c3d84e7cd")),
-                               SourcePos:      0,
-                               Amount:         20,
-                               ControlProgram: mustCreateP2WMCProgram(eth, testutil.MustDecodeHexString("52"), 53, 1),
+                       desc:       "full matched",
+                       tradePairs: []*common.TradePair{btc2eth, eth2btc},
+                       initStoreOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Btc2EthOrders[1],
+                               mock.Eth2BtcOrders[0],
                        },
-               },
-
-               // eth -> btc
-               {
-                       FromAssetID: &eth,
-                       ToAssetID:   &btc,
-                       Rate:        1 / 51.0,
-                       Utxo: &common.MovUtxo{
-                               SourceID:       hashPtr(testutil.MustDecodeHash("fba43ff5155209cb1769e2ec0e1d4a33accf899c740865edfc6d1de39b873b29")),
-                               SourcePos:      0,
-                               Amount:         510,
-                               ControlProgram: mustCreateP2WMCProgram(btc, testutil.MustDecodeHexString("53"), 1, 51.0),
+                       wantMatchedTxs: []*types.Tx{
+                               mock.MatchedTxs[1],
                        },
                },
                {
-                       FromAssetID: &eth,
-                       ToAssetID:   &btc,
-                       Rate:        1 / 52.0,
-                       Utxo: &common.MovUtxo{
-                               SourceID:       hashPtr(testutil.MustDecodeHash("05f24bb847db823075d81786aa270748e02602199cd009c0284f928503846a5a")),
-                               SourcePos:      0,
-                               Amount:         416,
-                               ControlProgram: mustCreateP2WMCProgram(btc, testutil.MustDecodeHexString("54"), 1, 52.0),
+                       desc:       "partial matched",
+                       tradePairs: []*common.TradePair{btc2eth, eth2btc},
+                       initStoreOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Btc2EthOrders[1],
+                               mock.Eth2BtcOrders[1],
                        },
-               },
-               {
-                       FromAssetID: &eth,
-                       ToAssetID:   &btc,
-                       Rate:        1 / 54.0,
-                       Utxo: &common.MovUtxo{
-                               SourceID:       hashPtr(testutil.MustDecodeHash("119a02980796dc352cf6475457463aef5666f66622088de3551fa73a65f0d201")),
-                               SourcePos:      0,
-                               Amount:         810,
-                               ControlProgram: mustCreateP2WMCProgram(btc, testutil.MustDecodeHexString("55"), 1, 54.0),
+                       wantMatchedTxs: []*types.Tx{
+                               mock.MatchedTxs[0],
                        },
                },
-       }
-)
-
-func TestGenerateMatchedTxs(t *testing.T) {
-       btc2eth := &common.TradePair{FromAssetID: &btc, ToAssetID: &eth}
-       eth2btc := &common.TradePair{FromAssetID: &eth, ToAssetID: &btc}
-
-       cases := []struct {
-               desc           string
-               tradePair      *common.TradePair
-               storeOrderMap  map[string][]*common.Order
-               wantMatchedTxs []*types.TxData
-       }{
                {
-                       desc:      "full matched",
-                       tradePair: &common.TradePair{FromAssetID: &btc, ToAssetID: &eth},
-                       storeOrderMap: map[string][]*common.Order{
-                               btc2eth.Key(): {orders[0], orders[1]},
-                               eth2btc.Key(): {orders[2], orders[3]},
+                       desc:       "partial matched and continue to match",
+                       tradePairs: []*common.TradePair{btc2eth, eth2btc},
+                       initStoreOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Btc2EthOrders[1],
+                               mock.Eth2BtcOrders[2],
                        },
-                       wantMatchedTxs: []*types.TxData{
-                               {
-                                       Inputs: []*types.TxInput{
-                                               types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(1)}, *orders[0].Utxo.SourceID, *orders[0].FromAssetID, orders[0].Utxo.Amount, orders[0].Utxo.SourcePos, orders[0].Utxo.ControlProgram),
-                                               types.NewSpendInput([][]byte{vm.Int64Bytes(1), vm.Int64Bytes(1)}, *orders[2].Utxo.SourceID, *orders[2].FromAssetID, orders[2].Utxo.Amount, orders[2].Utxo.SourcePos, orders[2].Utxo.ControlProgram),
-                                       },
-                                       Outputs: []*types.TxOutput{
-                                               types.NewIntraChainOutput(*orders[0].ToAssetID, 500, testutil.MustDecodeHexString("51")),
-                                               types.NewIntraChainOutput(*orders[2].ToAssetID, 10, testutil.MustDecodeHexString("53")),
-                                               types.NewIntraChainOutput(*orders[0].ToAssetID, 10, []byte{0x51}),
-                                       },
-                               },
+                       wantMatchedTxs: []*types.Tx{
+                               mock.MatchedTxs[2],
+                               mock.MatchedTxs[3],
                        },
                },
                {
-                       desc:      "partial matched",
-                       tradePair: &common.TradePair{FromAssetID: &btc, ToAssetID: &eth},
-                       storeOrderMap: map[string][]*common.Order{
-                               btc2eth.Key(): {orders[0], orders[1]},
-                               eth2btc.Key(): {orders[3]},
-                       },
-                       wantMatchedTxs: []*types.TxData{
-                               {
-                                       Inputs: []*types.TxInput{
-                                               types.NewSpendInput([][]byte{vm.Int64Bytes(416), vm.Int64Bytes(0), vm.Int64Bytes(0)}, *orders[0].Utxo.SourceID, *orders[0].FromAssetID, orders[0].Utxo.Amount, orders[0].Utxo.SourcePos, orders[0].Utxo.ControlProgram),
-                                               types.NewSpendInput([][]byte{vm.Int64Bytes(2), vm.Int64Bytes(1)}, *orders[3].Utxo.SourceID, *orders[3].FromAssetID, orders[3].Utxo.Amount, orders[3].Utxo.SourcePos, orders[3].Utxo.ControlProgram),
-                                       },
-                                       Outputs: []*types.TxOutput{
-                                               types.NewIntraChainOutput(*orders[0].ToAssetID, 416, testutil.MustDecodeHexString("51")),
-                                               // re-order
-                                               types.NewIntraChainOutput(*orders[0].FromAssetID, 2, orders[0].Utxo.ControlProgram),
-                                               types.NewIntraChainOutput(*orders[3].ToAssetID, 8, testutil.MustDecodeHexString("54")),
-                                       },
-                               },
+                       desc:       "unable to match",
+                       tradePairs: []*common.TradePair{btc2eth, eth2btc},
+                       initStoreOrders: []*common.Order{
+                               mock.Btc2EthOrders[1],
+                               mock.Eth2BtcOrders[0],
                        },
+                       wantMatchedTxs: []*types.Tx{},
                },
                {
-                       desc:      "partial matched and continue to match",
-                       tradePair: &common.TradePair{FromAssetID: &btc, ToAssetID: &eth},
-                       storeOrderMap: map[string][]*common.Order{
-                               btc2eth.Key(): {orders[0], orders[1]},
-                               eth2btc.Key(): {orders[4]},
+                       desc:       "cycle match",
+                       tradePairs: []*common.TradePair{btc2eth, eth2eos, eos2btc},
+                       initStoreOrders: []*common.Order{
+                               mock.Btc2EthOrders[0], mock.Eth2EosOrders[0], mock.Eos2BtcOrders[0],
                        },
-                       wantMatchedTxs: []*types.TxData{
-                               {
-                                       Inputs: []*types.TxInput{
-                                               types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(1)}, *orders[0].Utxo.SourceID, *orders[0].FromAssetID, orders[0].Utxo.Amount, orders[0].Utxo.SourcePos, orders[0].Utxo.ControlProgram),
-                                               types.NewSpendInput([][]byte{vm.Int64Bytes(10), vm.Int64Bytes(1), vm.Int64Bytes(0)}, *orders[4].Utxo.SourceID, *orders[4].FromAssetID, orders[4].Utxo.Amount, orders[4].Utxo.SourcePos, orders[4].Utxo.ControlProgram),
-                                       },
-                                       Outputs: []*types.TxOutput{
-                                               types.NewIntraChainOutput(*orders[0].ToAssetID, 500, testutil.MustDecodeHexString("51")),
-                                               types.NewIntraChainOutput(*orders[4].ToAssetID, 10, testutil.MustDecodeHexString("55")),
-                                               // re-order
-                                               types.NewIntraChainOutput(*orders[4].FromAssetID, 270, orders[4].Utxo.ControlProgram),
-                                               // fee
-                                               types.NewIntraChainOutput(*orders[4].FromAssetID, 27, []byte{0x51}),
-                                               // refund
-                                               types.NewIntraChainOutput(*orders[4].FromAssetID, 6, testutil.MustDecodeHexString("51")),
-                                               types.NewIntraChainOutput(*orders[4].FromAssetID, 7, testutil.MustDecodeHexString("55")),
-                                       },
-                               },
-                               {
-                                       Inputs: []*types.TxInput{
-                                               types.NewSpendInput([][]byte{vm.Int64Bytes(0), vm.Int64Bytes(0)}, *orders[1].Utxo.SourceID, *orders[1].FromAssetID, orders[1].Utxo.Amount, orders[1].Utxo.SourcePos, orders[1].Utxo.ControlProgram),
-                                               types.NewSpendInput([][]byte{vm.Int64Bytes(2), vm.Int64Bytes(1)}, testutil.MustDecodeHash("f47177c12d25f5316eb377ea006e77bf07e4f9646860e4641e313e004f9aa989"), *orders[4].FromAssetID, 270, 2, orders[4].Utxo.ControlProgram),
-                                       },
-                                       Outputs: []*types.TxOutput{
-                                               types.NewIntraChainOutput(*orders[1].ToAssetID, 270, testutil.MustDecodeHexString("52")),
-                                               // re-order
-                                               types.NewIntraChainOutput(*orders[1].FromAssetID, 15, orders[1].Utxo.ControlProgram),
-                                               types.NewIntraChainOutput(*orders[4].ToAssetID, 5, testutil.MustDecodeHexString("55")),
-                                       },
-                               },
+                       wantMatchedTxs: []*types.Tx{
+                               mock.MatchedTxs[6],
                        },
                },
        }
 
        for i, c := range cases {
-               movStore := &database.MockMovStore{OrderMap: c.storeOrderMap}
-               matchEngine := NewEngine(NewOrderTable(movStore, nil, nil), 0.05, []byte{0x51})
+               movStore := mock.NewMovStore([]*common.TradePair{btc2eth, eth2btc}, c.initStoreOrders)
+               matchEngine := NewEngine(NewOrderBook(movStore, nil, nil), 0.05, mock.NodeProgram)
                var gotMatchedTxs []*types.Tx
-               for matchEngine.HasMatchedTx(c.tradePair, c.tradePair.Reverse()) {
-                       matchedTx, err := matchEngine.NextMatchedTx(c.tradePair, c.tradePair.Reverse())
+               for matchEngine.HasMatchedTx(c.tradePairs...) {
+                       matchedTx, err := matchEngine.NextMatchedTx(c.tradePairs...)
                        if err != nil {
                                t.Fatal(err)
                        }
@@ -192,6 +97,10 @@ func TestGenerateMatchedTxs(t *testing.T) {
                }
 
                for i, gotMatchedTx := range gotMatchedTxs {
+                       if _, err := validation.ValidateTx(gotMatchedTx.Tx, &bc.Block{BlockHeader: &bc.BlockHeader{Version: 1}}); err != nil {
+                               t.Fatal(err)
+                       }
+
                        c.wantMatchedTxs[i].Version = 1
                        byteData, err := c.wantMatchedTxs[i].MarshalText()
                        if err != nil {
@@ -199,7 +108,7 @@ func TestGenerateMatchedTxs(t *testing.T) {
                        }
 
                        c.wantMatchedTxs[i].SerializedSize = uint64(len(byteData))
-                       wantMatchedTx := types.NewTx(*c.wantMatchedTxs[i])
+                       wantMatchedTx := types.NewTx(c.wantMatchedTxs[i].TxData)
                        if gotMatchedTx.ID != wantMatchedTx.ID {
                                t.Errorf("#%d(%s) the tx hash of got matched tx: %s is not equals want matched tx: %s", i, c.desc, gotMatchedTx.ID.String(), wantMatchedTx.ID.String())
                        }
@@ -207,21 +116,303 @@ func TestGenerateMatchedTxs(t *testing.T) {
        }
 }
 
-func mustCreateP2WMCProgram(requestAsset bc.AssetID, sellerProgram []byte, ratioMolecule, ratioDenominator int64) []byte {
-       contractArgs := vmutil.MagneticContractArgs{
-               RequestedAsset:   requestAsset,
-               RatioNumerator:   ratioMolecule,
-               RatioDenominator: ratioDenominator,
-               SellerProgram:    sellerProgram,
-               SellerKey:        testutil.MustDecodeHexString("ad79ec6bd3a6d6dbe4d0ee902afc99a12b9702fb63edce5f651db3081d868b75"),
+func TestCalcMatchedTxFee(t *testing.T) {
+       cases := []struct {
+               desc             string
+               tx               *types.TxData
+               maxFeeRate       float64
+               wantMatchedTxFee map[bc.AssetID]*MatchedTxFee
+       }{
+               {
+                       desc:             "fee less than max fee",
+                       maxFeeRate:       0.05,
+                       wantMatchedTxFee: map[bc.AssetID]*MatchedTxFee{mock.ETH: {FeeAmount: 10, MaxFeeAmount: 26}},
+                       tx:               &mock.MatchedTxs[1].TxData,
+               },
+               {
+                       desc:             "fee refund in tx",
+                       maxFeeRate:       0.05,
+                       wantMatchedTxFee: map[bc.AssetID]*MatchedTxFee{mock.ETH: {FeeAmount: 27, MaxFeeAmount: 27}},
+                       tx:               &mock.MatchedTxs[2].TxData,
+               },
+               {
+                       desc:             "fee is zero",
+                       maxFeeRate:       0.05,
+                       wantMatchedTxFee: map[bc.AssetID]*MatchedTxFee{},
+                       tx:               &mock.MatchedTxs[0].TxData,
+               },
        }
-       program, err := vmutil.P2WMCProgram(contractArgs)
-       if err != nil {
-               panic(err)
+
+       for i, c := range cases {
+               gotMatchedTxFee, err := CalcMatchedTxFee(c.tx, c.maxFeeRate)
+               if err != nil {
+                       t.Fatal(err)
+               }
+
+               if !testutil.DeepEqual(gotMatchedTxFee, c.wantMatchedTxFee) {
+                       t.Errorf("#%d(%s):fail to caculate matched tx fee, got (%v), want (%v)", i, c.desc, gotMatchedTxFee, c.wantMatchedTxFee)
+               }
        }
-       return program
 }
 
-func hashPtr(hash bc.Hash) *bc.Hash {
-       return &hash
+func TestValidateTradePairs(t *testing.T) {
+       cases := []struct {
+               desc       string
+               tradePairs []*common.TradePair
+               wantError  bool
+       }{
+               {
+                       desc: "valid case of two trade pairs",
+                       tradePairs: []*common.TradePair{
+                               {
+                                       FromAssetID: &mock.BTC,
+                                       ToAssetID:   &mock.ETH,
+                               },
+                               {
+                                       FromAssetID: &mock.ETH,
+                                       ToAssetID:   &mock.BTC,
+                               },
+                       },
+                       wantError: false,
+               },
+               {
+                       desc: "invalid case of two trade pairs",
+                       tradePairs: []*common.TradePair{
+                               {
+                                       FromAssetID: &mock.BTC,
+                                       ToAssetID:   &mock.ETH,
+                               },
+                               {
+                                       FromAssetID: &mock.ETH,
+                                       ToAssetID:   &mock.EOS,
+                               },
+                       },
+                       wantError: true,
+               },
+               {
+                       desc: "valid case of three trade pairs",
+                       tradePairs: []*common.TradePair{
+                               {
+                                       FromAssetID: &mock.BTC,
+                                       ToAssetID:   &mock.ETH,
+                               },
+                               {
+                                       FromAssetID: &mock.ETH,
+                                       ToAssetID:   &mock.EOS,
+                               },
+                               {
+                                       FromAssetID: &mock.EOS,
+                                       ToAssetID:   &mock.BTC,
+                               },
+                       },
+                       wantError: false,
+               },
+               {
+                       desc: "invalid case of three trade pairs",
+                       tradePairs: []*common.TradePair{
+                               {
+                                       FromAssetID: &mock.BTC,
+                                       ToAssetID:   &mock.ETH,
+                               },
+                               {
+                                       FromAssetID: &mock.ETH,
+                                       ToAssetID:   &mock.BTC,
+                               },
+                               {
+                                       FromAssetID: &mock.BTC,
+                                       ToAssetID:   &mock.BTC,
+                               },
+                       },
+                       wantError: true,
+               },
+               {
+                       desc: "valid case 2 of three trade pairs",
+                       tradePairs: []*common.TradePair{
+                               {
+                                       FromAssetID: &mock.BTC,
+                                       ToAssetID:   &mock.ETH,
+                               },
+                               {
+                                       FromAssetID: &mock.EOS,
+                                       ToAssetID:   &mock.BTC,
+                               },
+                               {
+                                       FromAssetID: &mock.ETH,
+                                       ToAssetID:   &mock.EOS,
+                               },
+                       },
+                       wantError: false,
+               },
+       }
+
+       for i, c := range cases {
+               err := validateTradePairs(c.tradePairs)
+               if c.wantError && err == nil {
+                       t.Errorf("#%d(%s): want error, got no error", i, c.desc)
+               }
+
+               if !c.wantError && err != nil {
+                       t.Errorf("#%d(%s): want no error, got error (%v)", i, c.desc, err)
+               }
+       }
+}
+
+func TestIsMatched(t *testing.T) {
+       cases := []struct {
+               desc        string
+               orders      []*common.Order
+               wantMatched bool
+       }{
+               {
+                       desc: "ratio is equals",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   6250,
+                                       RatioDenominator: 3,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   3,
+                                       RatioDenominator: 6250,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "ratio is equals, and numerator and denominator are multiples of the opposite",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   6250,
+                                       RatioDenominator: 3,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   9,
+                                       RatioDenominator: 18750,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "matched with a slight diff",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   62500000000000000,
+                                       RatioDenominator: 30000000000001,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   3,
+                                       RatioDenominator: 6250,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "not matched with a slight diff",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   62500000000000001,
+                                       RatioDenominator: 30000000000000,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   3,
+                                       RatioDenominator: 6250,
+                               },
+                       },
+                       wantMatched: false,
+               },
+               {
+                       desc: "ring matched",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   2000000003,
+                                       RatioDenominator: 100000001,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.EOS,
+                                       RatioNumerator:   400000000001,
+                                       RatioDenominator: 2000000003,
+                               },
+                               {
+                                       FromAssetID:      &mock.EOS,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   100000001,
+                                       RatioDenominator: 400000000001,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "ring matched with a slight diff",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   2000000003,
+                                       RatioDenominator: 100000001,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.EOS,
+                                       RatioNumerator:   400000000001,
+                                       RatioDenominator: 2000000003,
+                               },
+                               {
+                                       FromAssetID:      &mock.EOS,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   100000000,
+                                       RatioDenominator: 400000000001,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "ring fail matched with a slight diff",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   2000000003,
+                                       RatioDenominator: 100000001,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.EOS,
+                                       RatioNumerator:   400000000001,
+                                       RatioDenominator: 2000000003,
+                               },
+                               {
+                                       FromAssetID:      &mock.EOS,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   100000002,
+                                       RatioDenominator: 400000000001,
+                               },
+                       },
+                       wantMatched: false,
+               },
+       }
+
+       for i, c := range cases {
+               gotMatched := IsMatched(c.orders)
+               if gotMatched != c.wantMatched {
+                       t.Errorf("#%d(%s) got matched:%v, want matched:%v", i, c.desc, gotMatched, c.wantMatched)
+               }
+       }
 }