Skip to content

Commit

Permalink
refactor(x/ecocredit): clean up sell order messages (#1668)
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanchristo authored Dec 12, 2022
1 parent 11cb236 commit 9e3144b
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 38 deletions.
22 changes: 14 additions & 8 deletions x/ecocredit/marketplace/keeper/msg_sell.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (k Keeper) Sell(ctx context.Context, req *types.MsgSell) (*types.MsgSellRes
batch, err := k.baseStore.BatchTable().GetByDenom(ctx, order.BatchDenom)
if err != nil {
return nil, sdkerrors.ErrInvalidRequest.Wrapf(
"%s: batch denom %s: %s", orderIndex, order.BatchDenom, err.Error(),
"%s: batch denom %s: %s", orderIndex, order.BatchDenom, err,
)
}

Expand All @@ -62,10 +62,12 @@ func (k Keeper) Sell(ctx context.Context, req *types.MsgSell) (*types.MsgSellRes
return nil, err
}

// convert seller balance tradable credits to escrowed credits
if err = k.escrowCredits(ctx, orderIndex, sellerAcc, batch.Key, sellQty); err != nil {
return nil, err
}

// check if ask price denom is an allowed denom
allowed, err := isDenomAllowed(ctx, order.AskPrice.Denom, k.stateStore.AllowedDenomTable())
if err != nil {
return nil, err
Expand Down Expand Up @@ -109,7 +111,7 @@ func (k Keeper) Sell(ctx context.Context, req *types.MsgSell) (*types.MsgSellRes
return &types.MsgSellResponse{SellOrderIds: sellOrderIDs}, nil
}

// getOrCreateMarketID attempts to get a market, creating one otherwise, and return the Id.
// getOrCreateMarketID attempts to get a market, otherwise creating a market, and returns the ID.
func (k Keeper) getOrCreateMarketID(ctx context.Context, creditTypeAbbrev, bankDenom string) (uint64, error) {
market, err := k.stateStore.MarketTable().GetByCreditTypeAbbrevBankDenom(ctx, creditTypeAbbrev, bankDenom)
switch err {
Expand All @@ -126,38 +128,42 @@ func (k Keeper) getOrCreateMarketID(ctx context.Context, creditTypeAbbrev, bankD
}
}

func (k Keeper) escrowCredits(ctx context.Context, orderIndex string, account sdk.AccAddress, batchKey uint64, quantity math.Dec) error {
bal, err := k.baseStore.BatchBalanceTable().Get(ctx, account, batchKey)
// escrowCredits updates seller balance, subtracting the provided quantity from tradable amount
// and adding it to escrowed amount.
func (k Keeper) escrowCredits(ctx context.Context, orderIndex string, sellerAcc sdk.AccAddress, batchKey uint64, quantity math.Dec) error {

// get seller balance to be updated
bal, err := k.baseStore.BatchBalanceTable().Get(ctx, sellerAcc, batchKey)
if err != nil {
return ecocredit.ErrInsufficientCredits.Wrapf(
"%s: credit quantity: %v, tradable balance: 0", orderIndex, quantity,
)
}

// calculate and set seller balance tradable amount (subtract credits)
tradable, err := math.NewDecFromString(bal.TradableAmount)
if err != nil {
return err
}

newTradable, err := math.SafeSubBalance(tradable, quantity)
if err != nil {
return ecocredit.ErrInsufficientCredits.Wrapf(
"%s: credit quantity: %v, tradable balance: %v", orderIndex, quantity, tradable,
)
}
bal.TradableAmount = newTradable.String()

// calculate and set seller balance escrowed amount (add credits)
escrowed, err := math.NewDecFromString(bal.EscrowedAmount)
if err != nil {
return err
}

newEscrowed, err := math.SafeAddBalance(escrowed, quantity)
if err != nil {
return err
}

bal.TradableAmount = newTradable.String()
bal.EscrowedAmount = newEscrowed.String()

// update seller balance with new tradable and escrowed amounts
return k.baseStore.BatchBalanceTable().Update(ctx, bal)
}
67 changes: 42 additions & 25 deletions x/ecocredit/marketplace/keeper/msg_update_sell_orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,35 +33,47 @@ func (k Keeper) UpdateSellOrders(ctx context.Context, req *types.MsgUpdateSellOr

sellOrder, err := k.stateStore.SellOrderTable().Get(ctx, update.SellOrderId)
if err != nil {
return nil, sdkerrors.ErrInvalidRequest.Wrapf("%s: sell order with id %d: %s", updateIndex, update.SellOrderId, err.Error())
return nil, sdkerrors.ErrInvalidRequest.Wrapf("%s: sell order with id %d: %s", updateIndex, update.SellOrderId, err)
}

sellOrderAddr := sdk.AccAddress(sellOrder.Seller)
if !seller.Equals(sellOrderAddr) {
return nil, sdkerrors.ErrUnauthorized.Wrapf("%s: seller must be the seller of the sell order", updateIndex)
}

// apply the updates to the sell order
if err = k.applySellOrderUpdates(ctx, updateIndex, sellOrder, update); err != nil {
return nil, err
}
}

return &types.MsgUpdateSellOrdersResponse{}, nil
}

// applySellOrderUpdates applies the updates to the order.
func (k Keeper) applySellOrderUpdates(ctx context.Context, updateIndex string, order *api.SellOrder, update *types.MsgUpdateSellOrders_Update) error {
sdkCtx := sdk.UnwrapSDKContext(ctx)

var creditType *baseapi.CreditType
order.Maker = true // maker is always true for sell orders

// set order disable auto-retire based on update, note that if the update does
// include disable auto-retire, disable auto-retire will be updated to false
order.DisableAutoRetire = update.DisableAutoRetire

// get credit type from batch key to get/create market and check precision
creditType, err := k.getCreditTypeFromBatchKey(ctx, order.BatchKey)
if err != nil {
return err
}

if update.NewAskPrice != nil {
// get market to check if new ask price denom is an allowed denom
market, err := k.stateStore.MarketTable().Get(ctx, order.MarketId)
if err != nil {
return err
}

// check if new ask price denom is an allowed denom
allowed, err := isDenomAllowed(ctx, update.NewAskPrice.Denom, k.stateStore.AllowedDenomTable())
if err != nil {
return err
Expand All @@ -74,17 +86,14 @@ func (k Keeper) applySellOrderUpdates(ctx context.Context, updateIndex string, o
}

if market.BankDenom != update.NewAskPrice.Denom {
creditType, err = k.getCreditTypeFromBatchKey(ctx, order.BatchKey)
if err != nil {
return err
}
marketID, err := k.getOrCreateMarketID(ctx, creditType.Abbreviation, update.NewAskPrice.Denom)
if err != nil {
return err
}
order.MarketId = marketID
}

// set order ask amount to new ask price amount
order.AskAmount = update.NewAskPrice.Amount.String()
}

Expand All @@ -100,52 +109,60 @@ func (k Keeper) applySellOrderUpdates(ctx context.Context, updateIndex string, o
updateIndex, update.NewExpiration,
)
}

// set order expiration to new expiration
order.Expiration = timestamppb.New(*update.NewExpiration)
}

if update.NewQuantity != "" {
if creditType == nil {
var err error
creditType, err = k.getCreditTypeFromBatchKey(ctx, order.BatchKey)
if err != nil {
return err
}
}
newQty, err := math.NewPositiveFixedDecFromString(update.NewQuantity, creditType.Precision)

// get decimal of new quantity
newQuantity, err := math.NewPositiveFixedDecFromString(update.NewQuantity, creditType.Precision)
if err != nil {
return err
}
existingQty, err := math.NewDecFromString(order.Quantity)

// get decimal of current quantity
currentQuantity, err := math.NewDecFromString(order.Quantity)
if err != nil {
return err
}
// compare newQty and the existingQty
// if newQty > existingQty, we need to increase our amount escrowed by the difference of new - existing.
// if newQty < existingQty we need to decrease our amount escrowed by the difference of existing - new.
switch newQty.Cmp(existingQty) {

// compare newQuantity and currentQuantity
// if newQuantity > currentQuantity, we need to increase escrowed amount by the difference.
// if newQuantity < currentQuantity, we need to decrease escrowed amount by the difference.
switch newQuantity.Cmp(currentQuantity) {
case math.GreaterThan:
amtToEscrow, err := newQty.Sub(existingQty)
// calculate quantity of credits to escrow
escrowQuantity, err := newQuantity.Sub(currentQuantity)
if err != nil {
return err
}
if err = k.escrowCredits(ctx, updateIndex, order.Seller, order.BatchKey, amtToEscrow); err != nil {

// convert seller balance tradable credits to escrowed credits
if err = k.escrowCredits(ctx, updateIndex, order.Seller, order.BatchKey, escrowQuantity); err != nil {
return err
}

// set order quantity to new quantity
order.Quantity = update.NewQuantity
case math.LessThan:
amtToUnescrow, err := existingQty.Sub(newQty)
unescrowQuantity, err := currentQuantity.Sub(newQuantity)
if err != nil {
return err
}
if err = k.unescrowCredits(ctx, order.Seller, order.BatchKey, amtToUnescrow.String()); err != nil {

// convert seller balance escrowed credits to tradable credits
if err = k.unescrowCredits(ctx, order.Seller, order.BatchKey, unescrowQuantity.String()); err != nil {
return err
}

// set order quantity to new quantity
order.Quantity = update.NewQuantity
}
}

order.Maker = true // maker is always true for sell orders

// update sell order with new sell order properties
if err := k.stateStore.SellOrderTable().Update(ctx, order); err != nil {
return err
}
Expand Down
12 changes: 7 additions & 5 deletions x/ecocredit/marketplace/keeper/prune_sell_orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ func (k Keeper) PruneSellOrders(ctx context.Context) error {
return k.stateStore.SellOrderTable().DeleteRange(ctx, fromKey, toKey)
}

// unescrowCredits moves `amount` of credits from the sellerAddr's escrowed balance, into their tradable balance.
func (k Keeper) unescrowCredits(ctx context.Context, sellerAddr sdk.AccAddress, batchKey uint64, amount string) error {
// unescrowCredits updates seller balance, subtracting the provided quantity from escrowed amount
// and adding it to tradable amount.
func (k Keeper) unescrowCredits(ctx context.Context, sellerAddr sdk.AccAddress, batchKey uint64, quantity string) error {

creditAmt, err := math.NewDecFromString(amount)
quantityDec, err := math.NewDecFromString(quantity)
if err != nil {
return err
}
Expand All @@ -60,14 +61,15 @@ func (k Keeper) unescrowCredits(ctx context.Context, sellerAddr sdk.AccAddress,
return "", "", err
}

escrowedDec, err = math.SafeSubBalance(escrowedDec, creditAmt)
escrowedDec, err = math.SafeSubBalance(escrowedDec, quantityDec)
if err != nil {
return "", "", err
}
tradableDec, err = math.SafeAddBalance(tradableDec, creditAmt)
tradableDec, err = math.SafeAddBalance(tradableDec, quantityDec)
if err != nil {
return "", "", err
}

return escrowedDec.String(), tradableDec.String(), nil
}

Expand Down

0 comments on commit 9e3144b

Please sign in to comment.