Skip to content

Commit

Permalink
BE-586 | claimbot/order.go tests
Browse files Browse the repository at this point in the history
  • Loading branch information
deividaspetraitis committed Oct 14, 2024
1 parent f37ac1d commit ad494d3
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 16 deletions.
5 changes: 5 additions & 0 deletions domain/mocks/orderbook_grpc_client_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ type OrderbookGRPCClientMock struct {
FetchTicksCb func(ctx context.Context, chunkSize int, contractAddress string, tickIDs []int64) ([]orderbookdomain.Tick, error)
}

func (o *OrderbookGRPCClientMock) WithGetOrdersByTickCb(orders orderbookdomain.Orders, err error) {
o.GetOrdersByTickCb = func(ctx context.Context, contractAddress string, tick int64) (orderbookdomain.Orders, error) {
return orders, err
}
}
func (o *OrderbookGRPCClientMock) GetOrdersByTick(ctx context.Context, contractAddress string, tick int64) (orderbookdomain.Orders, error) {
if o.GetOrdersByTickCb != nil {
return o.GetOrdersByTickCb(ctx, contractAddress, tick)
Expand Down
6 changes: 6 additions & 0 deletions domain/mocks/orderbook_repository_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ func (m *OrderbookRepositoryMock) StoreTicks(poolID uint64, ticksMap map[int64]o
panic("StoreTicks not implemented")
}

func (m *OrderbookRepositoryMock) WithGetAllTicksFunc(ticks map[int64]orderbookdomain.OrderbookTick, ok bool) {
m.GetAllTicksFunc = func(poolID uint64) (map[int64]orderbookdomain.OrderbookTick, bool) {
return ticks, ok
}
}

// GetAllTicks implements OrderBookRepository.
func (m *OrderbookRepositoryMock) GetAllTicks(poolID uint64) (map[int64]orderbookdomain.OrderbookTick, bool) {
if m.GetAllTicksFunc != nil {
Expand Down
5 changes: 5 additions & 0 deletions domain/mocks/orderbook_usecase_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ func (m *OrderbookUsecaseMock) GetActiveOrdersStream(ctx context.Context, addres
}
panic("unimplemented")
}
func (m *OrderbookUsecaseMock) WithCreateFormattedLimitOrder(order orderbookdomain.LimitOrder, err error) {
m.CreateFormattedLimitOrderFunc = func(domain.CanonicalOrderBooksResult, orderbookdomain.Order) (orderbookdomain.LimitOrder, error) {
return order, err
}
}

func (m *OrderbookUsecaseMock) CreateFormattedLimitOrder(orderbook domain.CanonicalOrderBooksResult, order orderbookdomain.Order) (orderbookdomain.LimitOrder, error) {
if m.CreateFormattedLimitOrderFunc != nil {
Expand Down
28 changes: 25 additions & 3 deletions ingest/usecase/plugins/orderbook/claimbot/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,37 @@ package claimbot
import (
"context"

"github.com/osmosis-labs/osmosis/osmomath"
"github.com/osmosis-labs/sqs/delivery/grpc"
"github.com/osmosis-labs/sqs/domain"
authtypes "github.com/osmosis-labs/sqs/domain/cosmos/auth/types"
sqstx "github.com/osmosis-labs/sqs/domain/cosmos/tx"
"github.com/osmosis-labs/sqs/domain/keyring"
"github.com/osmosis-labs/sqs/domain/mvc"
orderbookdomain "github.com/osmosis-labs/sqs/domain/orderbook"
orderbookgrpcclientdomain "github.com/osmosis-labs/sqs/domain/orderbook/grpcclient"
"github.com/osmosis-labs/sqs/log"

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

// Order is order alias data structure for testing purposes.
type Order = order

// ProcessOrderbooksAndGetClaimableOrders is test wrapper for processOrderbooksAndGetClaimableOrders.
// This function is exported for testing purposes.
func ProcessOrderbooksAndGetClaimableOrders(
ctx context.Context,
fillThreshold osmomath.Dec,
orderbooks []domain.CanonicalOrderBooksResult,
orderbookRepository orderbookdomain.OrderBookRepository,
orderBookClient orderbookgrpcclientdomain.OrderBookClient,
orderbookusecase mvc.OrderBookUsecase,
logger log.Logger,
) []Order {
return processOrderbooksAndGetClaimableOrders(ctx, fillThreshold, orderbooks, orderbookRepository, orderBookClient, orderbookusecase, logger)
}

// buildTxFunc is a function signature for buildTx.
// This type is used only for testing purposes.
type BuildTx = buildTxFunc
Expand All @@ -32,7 +54,7 @@ func SetSendTx(fn sendTxFunc) {
sendTx = fn
}

// SendBatchClaimTx prepares and sends a batch claim transaction to the blockchain.
// SendBatchClaimTx a test wrapper for sendBatchClaimTx.
// This function is used only for testing purposes.
func SendBatchClaimTx(
ctx context.Context,
Expand All @@ -45,13 +67,13 @@ func SendBatchClaimTx(
return sendBatchClaimTx(ctx, keyring, grpcClient, accountQueryClient, contractAddress, claims)
}

// GetAccount retrieves account information for a given address.
// GetAccount is a test wrapper for getAccount.
// This function is exported for testing purposes.
func GetAccount(ctx context.Context, client authtypes.QueryClient, address string) (sqstx.Account, error) {
return getAccount(ctx, client, address)
}

// PrepareBatchClaimMsg prepares a batch claim message for the claimbot.
// PrepareBatchClaimMsg is a test wrapper for prepareBatchClaimMsg.
// This function is exported for testing purposes.
func PrepareBatchClaimMsg(claims orderbookdomain.Orders) ([]byte, error) {
return prepareBatchClaimMsg(claims)
Expand Down
22 changes: 13 additions & 9 deletions ingest/usecase/plugins/orderbook/claimbot/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import (
"github.com/osmosis-labs/sqs/domain/mvc"
orderbookdomain "github.com/osmosis-labs/sqs/domain/orderbook"
orderbookgrpcclientdomain "github.com/osmosis-labs/sqs/domain/orderbook/grpcclient"
"go.uber.org/zap"

"github.com/osmosis-labs/sqs/log"

"go.uber.org/zap"
)

type order struct {
orderbook domain.CanonicalOrderBooksResult
orders orderbookdomain.Orders
err error
Orderbook domain.CanonicalOrderBooksResult
Orders orderbookdomain.Orders
Err error
}

// processOrderbooksAndGetClaimableOrders processes a list of orderbooks and returns claimable orders for each.
Expand Down Expand Up @@ -51,13 +51,13 @@ func processOrderbook(
claimable, err := getClaimableOrdersForOrderbook(ctx, fillThreshold, orderbook, orderbookRepository, orderBookClient, orderbookusecase, logger)
if err != nil {
return order{
orderbook: orderbook,
err: err,
Orderbook: orderbook,
Err: err,
}
}
return order{
orderbook: orderbook,
orders: claimable,
Orderbook: orderbook,
Orders: claimable,
}
}

Expand Down Expand Up @@ -131,12 +131,16 @@ func getClaimableOrders(
if isTickFullyFilled(tickValues) {
return orders
}

return filterClaimableOrders(orderbook, orders, fillThreshold, orderbookusecase, logger)
}

// isTickFullyFilled checks if a tick is fully filled by comparing its cumulative total value
// to its effective total amount swapped.
func isTickFullyFilled(tickValues orderbookdomain.TickValues) bool {
if len(tickValues.CumulativeTotalValue) == 0 || len(tickValues.EffectiveTotalAmountSwapped) == 0 {
return false // empty values, thus not fully filled
}
return tickValues.CumulativeTotalValue == tickValues.EffectiveTotalAmountSwapped
}

Expand Down
175 changes: 175 additions & 0 deletions ingest/usecase/plugins/orderbook/claimbot/order_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package claimbot_test

import (
"context"
"testing"

"github.com/osmosis-labs/osmosis/osmomath"
"github.com/osmosis-labs/sqs/domain"
"github.com/osmosis-labs/sqs/domain/mocks"
orderbookdomain "github.com/osmosis-labs/sqs/domain/orderbook"
"github.com/osmosis-labs/sqs/ingest/usecase/plugins/orderbook/claimbot"
"github.com/osmosis-labs/sqs/log"
"github.com/osmosis-labs/sqs/sqsdomain/cosmwasmpool"

"github.com/stretchr/testify/assert"
)

func TestProcessOrderbooksAndGetClaimableOrders(t *testing.T) {
newOrderbookTick := func(tickID int64) map[int64]orderbookdomain.OrderbookTick {
return map[int64]orderbookdomain.OrderbookTick{
tickID: {
Tick: &cosmwasmpool.OrderbookTick{
TickId: tickID,
},
},
}
}

newOrderbookFullyFilledTick := func(tickID int64, direction string) map[int64]orderbookdomain.OrderbookTick {
tick := orderbookdomain.OrderbookTick{
Tick: &cosmwasmpool.OrderbookTick{
TickId: tickID,
},
TickState: orderbookdomain.TickState{},
}

tickValue := orderbookdomain.TickValues{
CumulativeTotalValue: "100",
EffectiveTotalAmountSwapped: "100",
}

if direction == "bid" {
tick.TickState.BidValues = tickValue
} else {
tick.TickState.AskValues = tickValue
}

return map[int64]orderbookdomain.OrderbookTick{
tickID: tick,
}
}

newOrder := func(direction string) orderbookdomain.Order {
return orderbookdomain.Order{
TickId: 1,
OrderId: 1,
OrderDirection: direction,
}
}

newLimitOrder := func(percentFilled osmomath.Dec) orderbookdomain.LimitOrder {
return orderbookdomain.LimitOrder{
OrderId: 1,
PercentFilled: percentFilled,
}
}

newCanonicalOrderBooksResult := func(poolID uint64, contractAddress string) domain.CanonicalOrderBooksResult {
return domain.CanonicalOrderBooksResult{PoolID: poolID, ContractAddress: contractAddress}
}

tests := []struct {
name string
fillThreshold osmomath.Dec
orderbooks []domain.CanonicalOrderBooksResult
mockSetup func(*mocks.OrderbookRepositoryMock, *mocks.OrderbookGRPCClientMock, *mocks.OrderbookUsecaseMock)
expectedOrders []claimbot.Order
}{
{
name: "No orderbooks",
fillThreshold: osmomath.NewDec(1),
orderbooks: []domain.CanonicalOrderBooksResult{},
mockSetup: func(repo *mocks.OrderbookRepositoryMock, client *mocks.OrderbookGRPCClientMock, usecase *mocks.OrderbookUsecaseMock) {
repo.GetAllTicksFunc = func(poolID uint64) (map[int64]orderbookdomain.OrderbookTick, bool) {
return nil, false
}
},
expectedOrders: nil,
},
{
name: "Single orderbook with no claimable orders",
fillThreshold: osmomath.NewDecWithPrec(95, 2), // 0.95
orderbooks: []domain.CanonicalOrderBooksResult{
newCanonicalOrderBooksResult(10, "contract1"),
},
mockSetup: func(repository *mocks.OrderbookRepositoryMock, client *mocks.OrderbookGRPCClientMock, usecase *mocks.OrderbookUsecaseMock) {
repository.WithGetAllTicksFunc(newOrderbookTick(1), true)

client.WithGetOrdersByTickCb(orderbookdomain.Orders{
newOrder("ask"),
}, nil)

// Not claimable order, below threshold
usecase.WithCreateFormattedLimitOrder(newLimitOrder(osmomath.NewDecWithPrec(90, 2)), nil)
},
expectedOrders: []claimbot.Order{
{
Orderbook: newCanonicalOrderBooksResult(10, "contract1"), // orderbook with
Orders: nil, // no claimable orders
},
},
},
{
name: "Tick fully filled: all orders are claimable",
fillThreshold: osmomath.NewDecWithPrec(99, 2), // 0.99
orderbooks: []domain.CanonicalOrderBooksResult{
newCanonicalOrderBooksResult(38, "contract8"),
},
mockSetup: func(repository *mocks.OrderbookRepositoryMock, client *mocks.OrderbookGRPCClientMock, usecase *mocks.OrderbookUsecaseMock) {
repository.WithGetAllTicksFunc(newOrderbookFullyFilledTick(35, "bid"), true)

client.WithGetOrdersByTickCb(orderbookdomain.Orders{
newOrder("bid"),
}, nil)

usecase.WithCreateFormattedLimitOrder(newLimitOrder(osmomath.NewDecWithPrec(90, 2)), nil)
},
expectedOrders: []claimbot.Order{
{
Orderbook: newCanonicalOrderBooksResult(38, "contract8"),
Orders: orderbookdomain.Orders{newOrder("bid")},
},
},
},
{
name: "Orderbook with claimable orders",
fillThreshold: osmomath.NewDecWithPrec(95, 2), // 0.95
orderbooks: []domain.CanonicalOrderBooksResult{
newCanonicalOrderBooksResult(64, "contract58"),
},
mockSetup: func(repository *mocks.OrderbookRepositoryMock, client *mocks.OrderbookGRPCClientMock, usecase *mocks.OrderbookUsecaseMock) {
repository.WithGetAllTicksFunc(newOrderbookTick(42), true)

client.WithGetOrdersByTickCb(orderbookdomain.Orders{
newOrder("ask"),
}, nil)

// Claimable order, above threshold
usecase.WithCreateFormattedLimitOrder(newLimitOrder(osmomath.NewDecWithPrec(96, 2)), nil)
},
expectedOrders: []claimbot.Order{
{
Orderbook: newCanonicalOrderBooksResult(64, "contract58"),
Orders: orderbookdomain.Orders{newOrder("ask")},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
repository := mocks.OrderbookRepositoryMock{}
client := mocks.OrderbookGRPCClientMock{}
usecase := mocks.OrderbookUsecaseMock{}
logger := log.NoOpLogger{}

tt.mockSetup(&repository, &client, &usecase)

result := claimbot.ProcessOrderbooksAndGetClaimableOrders(ctx, tt.fillThreshold, tt.orderbooks, &repository, &client, &usecase, &logger)

assert.Equal(t, tt.expectedOrders, result)
})
}
}
8 changes: 4 additions & 4 deletions ingest/usecase/plugins/orderbook/claimbot/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,15 @@ func (o *claimbot) ProcessEndBlock(ctx context.Context, blockHeight uint64, meta
)

for _, orderbook := range orders {
if orderbook.err != nil {
fmt.Println("step1 error", orderbook.err)
if orderbook.Err != nil {
fmt.Println("step1 error", orderbook.Err)
continue
}

if err := o.processBatchClaimOrders(ctx, orderbook.orderbook, orderbook.orders); err != nil {
if err := o.processBatchClaimOrders(ctx, orderbook.Orderbook, orderbook.Orders); err != nil {
o.logger.Info(
"failed to process orderbook orders",
zap.String("contract_address", orderbook.orderbook.ContractAddress),
zap.String("contract_address", orderbook.Orderbook.ContractAddress),
zap.Error(err),
)
}
Expand Down

0 comments on commit ad494d3

Please sign in to comment.