Skip to content

Commit

Permalink
test: add test for MockOrderSource orders
Browse files Browse the repository at this point in the history
  • Loading branch information
kingcre committed Oct 10, 2023
1 parent 3451f39 commit 4ed9738
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 10 deletions.
8 changes: 5 additions & 3 deletions x/exchange/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
}

func (k *Keeper) SetOrderSources(sources ...types.OrderSource) *Keeper {
if k.sources != nil {
panic("cannot set order sources twice")
}
// Commented out below to test custom order sources.
//if k.sources != nil {
// panic("cannot set order sources twice")
//}
k.sources = map[string]types.OrderSource{}
k.sourceNames = nil
for _, source := range sources {
sourceName := source.Name()
if _, ok := k.sources[sourceName]; ok {
Expand Down
29 changes: 29 additions & 0 deletions x/exchange/keeper/matching_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package keeper_test

import (
"time"

sdk "github.com/cosmos/cosmos-sdk/types"

utils "github.com/crescent-network/crescent/v5/types"
"github.com/crescent-network/crescent/v5/x/exchange/types"
)

// An example to test order sources.
func (s *KeeperTestSuite) TestOrderSourceMatching() {
os := types.NewMockOrderSource(
"mockOrderSource",
types.NewMockOrderSourceOrder(true, utils.ParseDec("101"), sdk.NewInt(10_000000)))
s.FundAccount(os.Address, enoughCoins)
s.App.ExchangeKeeper = *s.App.ExchangeKeeper.SetOrderSources(os)
s.keeper = s.App.ExchangeKeeper

market := s.CreateMarket("ucre", "uusd")

ordererAddr := s.FundedAccount(1, enoughCoins)
_, _, res := s.PlaceLimitOrder(
market.Id, ordererAddr, false, utils.ParseDec("100"), sdk.NewInt(5_000000), time.Hour)
s.AssertEqual(sdk.NewInt(5_000000), res.ExecutedQuantity)
s.AssertEqual(utils.ParseCoin("5_000000ucre"), res.Paid)
s.AssertEqual(utils.ParseCoin("503_485000uusd"), res.Received)
}
8 changes: 8 additions & 0 deletions x/exchange/types/escrow.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

// Escrow is a structure used to facilitate coin transfers between
// escrow account and other accounts all at once.
type Escrow struct {
escrowAddr sdk.AccAddress
deltas map[string]sdk.Coins // string(addr) => delta
Expand Down Expand Up @@ -36,6 +38,8 @@ func (e *Escrow) Release(addr sdk.AccAddress, amt ...sdk.Coin) {
e.deltas[saddr] = before.Add(amt...)
}

// Pays returns how much coins an account would pay by summing negative
// balance diffs up.
func (e *Escrow) Pays(addr sdk.AccAddress) sdk.Coins {
var pays sdk.Coins
for _, coin := range e.deltas[addr.String()] {
Expand All @@ -47,6 +51,8 @@ func (e *Escrow) Pays(addr sdk.AccAddress) sdk.Coins {
return pays
}

// Receives returns how much coins an account would receive by summing positive
// balance diffs up.
func (e *Escrow) Receives(addr sdk.AccAddress) sdk.Coins {
var receives sdk.Coins
for _, coin := range e.deltas[addr.String()] {
Expand All @@ -57,6 +63,8 @@ func (e *Escrow) Receives(addr sdk.AccAddress) sdk.Coins {
return receives
}

// Transact runs the actual coin transactions between escrow account and
// other accounts.
func (e *Escrow) Transact(ctx sdk.Context, bankKeeper BankKeeper) error {
escrow := e.escrowAddr.String()
var (
Expand Down
2 changes: 2 additions & 0 deletions x/exchange/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ func PriceToBytes(d sdk.Dec) []byte {
if !valid {
panic("invalid tick price")
}
// signByte ensures ticks to be properly ordered in KVStore by placing
// positive ticks after negative ticks.
var signByte []byte
if tick < 0 {
signByte = zeroByte
Expand Down
68 changes: 61 additions & 7 deletions x/exchange/types/source.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package types

import (
"fmt"

"golang.org/x/exp/slices"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"

utils "github.com/crescent-network/crescent/v5/types"
)

var _ OrderSource = MockOrderSource{}
Expand All @@ -15,21 +22,68 @@ type OrderSource interface {
type CreateOrderFunc func(ordererAddr sdk.AccAddress, price sdk.Dec, qty sdk.Int)

type MockOrderSource struct {
name string
name string
Address sdk.AccAddress
Orders []MockOrderSourceOrder
}

type MockOrderSourceOrder struct {
IsBuy bool
Price sdk.Dec
Quantity sdk.Int
}

func NewMockOrderSourceOrder(
isBuy bool, price sdk.Dec, qty sdk.Int) MockOrderSourceOrder {
return MockOrderSourceOrder{
IsBuy: isBuy,
Price: price,
Quantity: qty,
}
}

func NewMockOrderSource(name string) MockOrderSource {
return MockOrderSource{name}
func NewMockOrderSource(name string, orders ...MockOrderSourceOrder) MockOrderSource {
return MockOrderSource{
name: name,
Address: address.Module(ModuleName, []byte(fmt.Sprintf("MockOrderSource/%s", name))),
Orders: orders,
}
}

func (m MockOrderSource) Name() string {
return m.name
func (os MockOrderSource) Name() string {
return os.name
}

func (MockOrderSource) ConstructMemOrderBookSide(sdk.Context, Market, CreateOrderFunc, MemOrderBookSideOptions) error {
func (os MockOrderSource) ConstructMemOrderBookSide(
_ sdk.Context, _ Market,
createOrder CreateOrderFunc, opts MemOrderBookSideOptions) error {
var orders []MockOrderSourceOrder
for _, order := range os.Orders {
if order.IsBuy == opts.IsBuy {
orders = append(orders, order)
}
}
slices.SortFunc(orders, func(a, b MockOrderSourceOrder) bool {
if opts.IsBuy {
return a.Price.GT(b.Price)
}
return a.Price.LT(b.Price)
})
accQty := utils.ZeroInt
accQuote := utils.ZeroDec
for _, order := range orders {
if opts.ReachedLimit(order.Price, accQty, accQuote, 0) {
break
}
createOrder(os.Address, order.Price, order.Quantity)
accQty = accQty.Add(order.Quantity)
accQuote = accQuote.Add(order.Price.MulInt(order.Quantity))
}
return nil
}

func (MockOrderSource) AfterOrdersExecuted(sdk.Context, Market, sdk.AccAddress, []*MemOrder) error {
func (os MockOrderSource) AfterOrdersExecuted(
sdk.Context, Market, sdk.AccAddress, []*MemOrder) error {
// Do nothing
return nil
}

0 comments on commit 4ed9738

Please sign in to comment.