Skip to content

Commit

Permalink
[1658]: Some pre-settlement validation.
Browse files Browse the repository at this point in the history
  • Loading branch information
SpicyLemon committed Sep 19, 2023
1 parent 86c2425 commit 47ad792
Showing 1 changed file with 82 additions and 22 deletions.
104 changes: 82 additions & 22 deletions x/exchange/keeper/orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,20 @@ func (k Keeper) CancelOrder(ctx sdk.Context, orderID uint64, signer string) erro
return ctx.EventManager().EmitTypedEvent(exchange.NewEventOrderCancelled(orderID, signerAddr))

Check warning on line 392 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L390-L392

Added lines #L390 - L392 were not covered by tests
}

// safeCoinsEquals returns true if the two provided coins are equal.
// Returns false instead of panicking like sdk.Coins.IsEqual.
func safeCoinsEquals(a, b sdk.Coins) (isEqual bool) {
// The sdk.Coins.IsEqual function will panic if a and b have the same number of entries, but different denoms.
// Really, that stuff is all pretty panic happy.
// In here, we don't really care why it panics, but if it does, they're not equal.
defer func() {
if r := recover(); r != nil {
isEqual = false
}

Check warning on line 404 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L397-L404

Added lines #L397 - L404 were not covered by tests
}()
return a.IsEqual(b)

Check warning on line 406 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L406

Added line #L406 was not covered by tests
}

// getBidOrders gets orders from the store, making sure they're bid orders in the given market
// and do not have the same buyer as the provided seller. If the seller isn't yet known, just provide "" for it.
func (k Keeper) getBidOrders(store sdk.KVStore, marketID uint32, orderIDs []uint64, seller string) ([]*exchange.Order, error) {
Expand Down Expand Up @@ -472,6 +486,16 @@ func (k Keeper) getAskOrders(store sdk.KVStore, marketID uint32, orderIDs []uint
return orders, errors.Join(errs...)

Check warning on line 486 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L486

Added line #L486 was not covered by tests
}

// sumAssetsAndPrice gets the sum of assets, and the sum of prices of the provided orders.
func sumAssetsAndPrice(orders []*exchange.Order) (sdk.Coins, sdk.Coins) {
var totalAssets, totalPrice sdk.Coins
for _, order := range orders {
totalAssets = totalAssets.Add(order.GetAssets()...)
totalPrice = totalPrice.Add(order.GetPrice())
}
return totalAssets, totalPrice

Check warning on line 496 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L490-L496

Added lines #L490 - L496 were not covered by tests
}

// FillBids settles one or more bid orders for a seller.
func (k Keeper) FillBids(ctx sdk.Context, msg *exchange.MsgFillBidsRequest) error {
if err := msg.ValidateBasic(); err != nil {
Expand Down Expand Up @@ -510,7 +534,7 @@ func (k Keeper) FillBids(ctx sdk.Context, msg *exchange.MsgFillBidsRequest) erro
}

Check warning on line 534 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L531-L534

Added lines #L531 - L534 were not covered by tests

var errs []error
var totalAssets, totalPrice, totalSellerFee sdk.Coins
var totalSellerFee sdk.Coins
assetOutputs := make([]banktypes.Output, 0, len(msg.BidOrderIds))
priceInputs := make([]banktypes.Input, 0, len(msg.BidOrderIds))
addrIndex := make(map[string]int)
Expand All @@ -525,16 +549,15 @@ func (k Keeper) FillBids(ctx sdk.Context, msg *exchange.MsgFillBidsRequest) erro

sellerRatioFee, rerr := calculateSellerSettlementRatioFee(store, marketID, price)
if rerr != nil {
errs = append(errs, fmt.Errorf("error calculating seller settlement ratio fee for order %d: %w", order.OrderId, rerr))
errs = append(errs, fmt.Errorf("error calculating seller settlement ratio fee for order %d: %w",
order.OrderId, rerr))
continue

Check warning on line 554 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L536-L554

Added lines #L536 - L554 were not covered by tests
}
if err := k.releaseHoldOnOrder(ctx, order); err != nil {
errs = append(errs, err)
continue

Check warning on line 558 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L556-L558

Added lines #L556 - L558 were not covered by tests
}

totalAssets = totalAssets.Add(assets...)
totalPrice = totalPrice.Add(price)
if sellerRatioFee != nil {
totalSellerFee = totalSellerFee.Add(*sellerRatioFee)
}

Check warning on line 563 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L561-L563

Added lines #L561 - L563 were not covered by tests
Expand Down Expand Up @@ -564,6 +587,8 @@ func (k Keeper) FillBids(ctx sdk.Context, msg *exchange.MsgFillBidsRequest) erro
return errors.Join(errs...)
}

Check warning on line 588 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L586-L588

Added lines #L586 - L588 were not covered by tests

totalAssets, totalPrice := sumAssetsAndPrice(orders)

if !safeCoinsEquals(totalAssets, msg.TotalAssets) {
return fmt.Errorf("total assets %q does not equal sum of bid order assets %q", msg.TotalAssets, totalAssets)
}

Check warning on line 594 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L590-L594

Added lines #L590 - L594 were not covered by tests
Expand Down Expand Up @@ -645,7 +670,6 @@ func (k Keeper) FillAsks(ctx sdk.Context, msg *exchange.MsgFillAsksRequest) erro
}

Check warning on line 670 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L667-L670

Added lines #L667 - L670 were not covered by tests

var errs []error
var totalAssets, totalPrice sdk.Coins
assetInputs := make([]banktypes.Input, 0, len(msg.AskOrderIds))
priceOutputs := make([]banktypes.Output, 0, len(msg.AskOrderIds))
addrIndex := make(map[string]int)
Expand All @@ -660,16 +684,15 @@ func (k Keeper) FillAsks(ctx sdk.Context, msg *exchange.MsgFillAsksRequest) erro

sellerRatioFee, rerr := calculateSellerSettlementRatioFee(store, marketID, price)
if rerr != nil {
errs = append(errs, fmt.Errorf("error calculating seller settlement ratio fee for order %d: %w", order.OrderId, rerr))
errs = append(errs, fmt.Errorf("error calculating seller settlement ratio fee for order %d: %w",
order.OrderId, rerr))
continue

Check warning on line 689 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L672-L689

Added lines #L672 - L689 were not covered by tests
}
if err := k.releaseHoldOnOrder(ctx, order); err != nil {
errs = append(errs, err)
continue

Check warning on line 693 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L691-L693

Added lines #L691 - L693 were not covered by tests
}

totalAssets = totalAssets.Add(assets...)
totalPrice = totalPrice.Add(price)
var totalSellerFee sdk.Coins
if sellerSettlementFlatFee != nil && !sellerSettlementFlatFee.IsZero() {
totalSellerFee = totalSellerFee.Add(*sellerSettlementFlatFee)
Expand Down Expand Up @@ -703,6 +726,8 @@ func (k Keeper) FillAsks(ctx sdk.Context, msg *exchange.MsgFillAsksRequest) erro
return errors.Join(errs...)
}

Check warning on line 727 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L725-L727

Added lines #L725 - L727 were not covered by tests

totalAssets, totalPrice := sumAssetsAndPrice(orders)

if !safeCoinsEquals(totalPrice, sdk.Coins{msg.TotalPrice}) {
return fmt.Errorf("total price %q does not equal sum of ask order prices %q", msg.TotalPrice, totalPrice)
}

Check warning on line 733 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L729-L733

Added lines #L729 - L733 were not covered by tests
Expand Down Expand Up @@ -743,21 +768,56 @@ func (k Keeper) FillAsks(ctx sdk.Context, msg *exchange.MsgFillAsksRequest) erro
return ctx.EventManager().EmitTypedEvents(events...)

Check warning on line 768 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L768

Added line #L768 was not covered by tests
}

// SettleOrders attempts to settle all the provided orders.
func (k Keeper) SettleOrders(ctx sdk.Context, marketID uint32, askOrderIDs, bidOrderIds []uint64, expectPartial bool) error {
store := k.getStore(ctx)
if err := validateMarketExists(store, marketID); err != nil {
return err
}

Check warning on line 776 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L772-L776

Added lines #L772 - L776 were not covered by tests

askOrders, aoerr := k.getAskOrders(store, marketID, askOrderIDs, "")
bidOrders, boerr := k.getBidOrders(store, marketID, bidOrderIds, "")
if aoerr != nil || boerr != nil {
return errors.Join(aoerr, boerr)
}

Check warning on line 782 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L778-L782

Added lines #L778 - L782 were not covered by tests

totalAssetsForSale, totalAskPrice := sumAssetsAndPrice(askOrders)
totalAssetsToBuy, totalBidPrice := sumAssetsAndPrice(bidOrders)

var errs []error
if len(totalAssetsForSale) != 1 {
errs = append(errs, fmt.Errorf("cannot settle with multiple ask order asset denoms %q", totalAssetsForSale))
}
if len(totalAskPrice) != 1 {
errs = append(errs, fmt.Errorf("cannot settle with multiple ask order price denoms %q", totalAskPrice))
}
if len(totalAssetsToBuy) != 1 {
errs = append(errs, fmt.Errorf("cannot settle with multiple bid order asset denoms %q", totalAssetsToBuy))
}
if len(totalBidPrice) != 1 {
errs = append(errs, fmt.Errorf("cannot settle with multiple bid order price denoms %q", totalBidPrice))
}
if len(errs) > 0 {
return errors.Join(errs...)
}

Check warning on line 802 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L784-L802

Added lines #L784 - L802 were not covered by tests

if totalAssetsForSale[0].Denom != totalAssetsToBuy[0].Denom {
errs = append(errs, fmt.Errorf("cannot settle different ask %q and bid %q asset denoms",
totalAssetsForSale, totalAssetsToBuy))
}
if totalAskPrice[0].Denom != totalBidPrice[0].Denom {
errs = append(errs, fmt.Errorf("cannot settle different ask %q and bid %q price denoms",
totalAskPrice, totalBidPrice))
}
if len(errs) > 0 {
return errors.Join(errs...)
}

Check warning on line 814 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L804-L814

Added lines #L804 - L814 were not covered by tests

if !expectPartial && !safeCoinsEquals(totalAssetsForSale, totalAssetsToBuy) {
return fmt.Errorf("total assets for sale %q does not equal total assets to buy %q",
totalAssetsForSale, totalAssetsToBuy)
}

Check warning on line 819 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L816-L819

Added lines #L816 - L819 were not covered by tests

// TODO[1658]: Implement SettleOrders.
panic("Not implemented")

Check warning on line 822 in x/exchange/keeper/orders.go

View check run for this annotation

Codecov / codecov/patch

x/exchange/keeper/orders.go#L822

Added line #L822 was not covered by tests
}

// safeCoinsEquals returns true if the two provided coins are equal.
// Returns false instead of panicking like sdk.Coins.IsEqual.
func safeCoinsEquals(a, b sdk.Coins) (isEqual bool) {
// The sdk.Coins.IsEqual function will panic if a and b have the same number of entries, but different denoms.
// Really, that stuff is all pretty panic happy.
// In here, we don't really care why it panics, but if it does, they're not equal.
defer func() {
if r := recover(); r != nil {
isEqual = false
}
}()
return a.IsEqual(b)
}

0 comments on commit 47ad792

Please sign in to comment.