Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(x/ecocredit): Msg Server implementation for buy/sell functionality #613

Merged
merged 29 commits into from
Nov 15, 2021

Conversation

clevinson
Copy link
Member

@clevinson clevinson commented Nov 2, 2021

Description

Closes: #603 #614 #622

This pull request implements the following:

  • proto type definitions for SellOrder, BuyOrder, and AskDenom
  • proto event definitions for EventSell, EventUpdateSellOrder, EventBuyOrderCreated, EventBuyOrderFilled, and EventAllowAskDenom
  • message service methods for Sell, UpdateSellOrders, Buy, and AllowAskDenom
  • ValidateBasic for MsgSell, MsgUpdateSellOrders, MsgBuy, and MsgAllowAskDenom

Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • included the correct type prefix in the PR title
  • added ! to the type prefix if API or client breaking change
  • targeted the correct branch (see PR Targeting)
  • provided a link to the relevant issue or specification
  • followed the guidelines for building modules
  • included the necessary unit and integration tests
  • added a changelog entry to CHANGELOG.md
  • included comments for documenting Go code
  • updated the relevant documentation or specification
  • reviewed "Files changed" and left comments if necessary
  • confirmed all CI checks have passed

Reviewers Checklist

All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.

I have...

  • confirmed the correct type prefix in the PR title
  • confirmed ! in the type prefix if API or client breaking change
  • confirmed all author checklist items have been addressed
  • reviewed state machine logic
  • reviewed API design and naming
  • reviewed documentation is accurate
  • reviewed tests and test coverage
  • manually tested (if applicable)

@clevinson clevinson marked this pull request as draft November 2, 2021 02:10
@codecov
Copy link

codecov bot commented Nov 4, 2021

Codecov Report

Merging #613 (6cc74fd) into master (8994951) will decrease coverage by 1.14%.
The diff coverage is 17.15%.

@@            Coverage Diff             @@
##           master     #613      +/-   ##
==========================================
- Coverage   75.23%   74.09%   -1.15%     
==========================================
  Files         104      104              
  Lines       14628    14899     +271     
==========================================
+ Hits        11006    11039      +33     
- Misses       2902     3131     +229     
- Partials      720      729       +9     
Flag Coverage Δ
experimental-codecov 74.09% <17.15%> (-1.15%) ⬇️
stable-codecov 65.88% <17.15%> (-1.14%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

@ryanchristo ryanchristo marked this pull request as ready for review November 6, 2021 00:27
x/ecocredit/msgs.go Outdated Show resolved Hide resolved

m.Orders[i].AskPrice.Validate()

if !m.Orders[i].AskPrice.Amount.IsPositive() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coins.Validate checks for negatives. just wondering, are we doing this to avoid 0 amt bids?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. The intention here was to prevent sell orders from being created with a 0 amount ask price and therefore buy orders with a 0 amount bid price (bid price must be ask price at minimum). I think this behavior is desired but let me know if you think otherwise.

Copy link
Member Author

@clevinson clevinson Nov 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dtkong thoughts here? @ryanchristo and I had thought that we didn't want to allow buy/sell orders w/ a 0 ask price. If there's a valid use case for it we can change this.

x/ecocredit/msgs.go Outdated Show resolved Hide resolved
x/ecocredit/msgs.go Outdated Show resolved Hide resolved

m.Updates[i].NewAskPrice.Validate()

if !m.Updates[i].NewAskPrice.Amount.IsPositive() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if anyone would ever do this, but would we want to allow credits to sell for 0 here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial thought was that we would not want to support 0 amount ask price but maybe we should?

x/ecocredit/server/msg_server.go Outdated Show resolved Hide resolved
x/ecocredit/server/msg_server.go Outdated Show resolved Hide resolved
x/ecocredit/server/msg_server.go Outdated Show resolved Hide resolved
@@ -577,3 +516,346 @@ func (s serverImpl) isCreatorAllowListed(ctx types.Context, allowlist []string,
}
return false
}

// Sell creates new sell orders for credits
func (s serverImpl) Sell(goCtx context.Context, req *ecocredit.MsgSell) (*ecocredit.MsgSellResponse, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im curious what will happen if a user creates multiple sell orders around the same credits. i think there is a concern with flooding the chain with a bunch of seemingly valid sell orders that are actually all but one invalid.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a valid concern. We discussed an escrow model as a potential alternative but at the moment we are only checking the credit balance at the time the sell order is created.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well maybe we should revisit the pros and cons and escrow. Can you guys think a little more about the pros and cons and the threat model here?

x/ecocredit/server/testsuite/suite.go Outdated Show resolved Hide resolved
x/ecocredit/msgs.go Outdated Show resolved Hide resolved
}

// EventBuy is an event emitted when a buy order is created.
message EventBuy {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have separate events when buy orders are created and filled?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would this work? We're not storing buy orders in state, so the created event would emit if partial or filled and the filled event would emit only if the buy order was filled?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this would work for orders with filters, where buy orders can be made for a credit with X characteristics, but no direct sell order ID listed.. but sounds like it wont work for orders with direct SellOrderId's as with those you either fill it or you don't.

Is there any spec on how the matching engine will work in this scheme for floating buy/sell orders?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the current implementation, it is possible to do a partial fill with a buy order that specifies a sell order id but I'm not sure what we should do with the buy order if the order was only partially filled.

At the moment, if partial fill is enabled, the buyer purchases the available credits from the given sell order and that's it (the buy order does not persist to state and there is no fulfilling the remainder of the order at a later point in time); if the buyer specifies more credits than what is available in the sell order, the buyer ends up purchasing only what is available.

When we implement the filtered option (#623), the same question applies. If partial fill is enabled and an order is only partially filled given the filter criteria, how will the buy order be fulfilled at a later point in time?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how will the buy order be fulfilled at a later point in time?

Just like in regular exchanges, if the buy order is partially filled it will stay open and way for new or updated sell orders. Basically in every processing batch an attempt will be made to match it with sell orders.

We should probably have expiration times for both sell and buy orders btw.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point we havn't implemented any of the ORM tables for storing buy orders in state, but sounds like we would need this in order to actually process partial-filling correctly (where we keep a buy order open). If we don't implement that in this PR we could also just add it in a follow-up. When persisting the partially filled buy order to state, how would we store the selection ? Would it still reference the original sell_order_id ? Afaiu, the sell order would be exhausted and then closed (removed from state), so there wouldn't be any way for a seller to top up their supply on an existing sell order. They would rather create a new sell order.

If we allow for partial fills I'm not really sure how we can keep those buy orders open seeing that they are against sell order which would have already closed..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we address in a follow-up, it might make sense to include with #623 assuming that we would only need to store a buy order if it was using the filter option (not a direct buy order).

I added a second event for filling buy orders to distinguish from creating buy orders. At the moment the second event seems unnecessary given that only direct buy orders are implemented in this pull request but it makes sense when we implement the filter option. I think this goes in line with #623 as well.

I also added a couple commits to update the remaining quantity if the buy order does not purchase all credits within the sell order and to delete the sell order if there are no remaining credits.

Maybe we should break out a separate issue for adding and handling expiration times..?

ryanchristo and others added 5 commits November 9, 2021 08:25
Co-authored-by: MD Aleem <72057206+aleem1314@users.noreply.github.com>
Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com>
Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com>
Comment on lines +772 to +774
if req.RootAddress != authtypes.NewModuleAddress(govtypes.ModuleName).String() {
return nil, sdkerrors.ErrUnauthorized.Wrap("root address must be governance module address")
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aaronc @blushi Can one of you confirm that this is how the root address stuff is supposed to work?

@ryanchristo
Copy link
Member

ryanchristo commented Nov 10, 2021

Ready for another round of reviews.

Aside from remaining items that already have issues, here are the remaining items that I can see for this pull request that could either be addressed here or in follow-up pull requests:

Let me know if you think any of these should be addressed here, otherwise I think it might be nice to include them in follow up issues.

Copy link
Contributor

@technicallyty technicallyty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regarding #613 (comment), i think it would make sense to include the buy order table here, just to set it up for the processing PR

x/ecocredit/server/msg_server.go Outdated Show resolved Hide resolved
x/ecocredit/server/msg_server.go Outdated Show resolved Hide resolved
x/ecocredit/server/msg_server.go Outdated Show resolved Hide resolved
x/ecocredit/server/msg_server.go Outdated Show resolved Hide resolved
x/ecocredit/server/msg_server.go Outdated Show resolved Hide resolved
ryanchristo and others added 3 commits November 11, 2021 15:06
Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com>
Copy link
Contributor

@technicallyty technicallyty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great work! 💯 💯 💯 💯 💯 💯 💯

Copy link
Member Author

@clevinson clevinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few small nits, otherwise giving this an ACK 🎉

@ryanchristo can you give an approval for me, since I authored the original PR ?

Comment on lines +202 to +203
// total_price is the total price for the purchased credits.
cosmos.base.v1beta1.Coin total_price = 5;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// total_price is the total price for the purchased credits.
cosmos.base.v1beta1.Coin total_price = 5;
// price is the total price for the purchased credits.
cosmos.base.v1beta1.Coin price = 5;

I like price instead of total_price, since its not like prices are summed (creating a "total")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The price here is the amount of coin sent (not the price per unit but the calculated amount of coin needed to fill the order). I thought it might help to use total to distinguish from bid price and ask price (per unit) more clearly.

Comment on lines +161 to +162
// sell_order_id is the sell order ID against which the buyer is trying to buy.
uint64 sell_order_id = 2;
Copy link
Member Author

@clevinson clevinson Nov 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine for now, but we'll eventually want to upgrade this to be either a sell_order_id or some selection criteria, right? I think we can just do so once we add buy orders based on a selection criteria.

No todo in this PR, I think we should just keep in mind to update the event when we add the rest of the buy order functionality.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. This will need to be updated when we introduce filtered buy orders. #623

@ryanchristo ryanchristo mentioned this pull request Nov 15, 2021
4 tasks
Copy link
Member

@ryanchristo ryanchristo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ryanchristo can you give an approval for me, since I authored the original PR ?

@ryanchristo ryanchristo merged commit 081ae07 into master Nov 15, 2021
@ryanchristo ryanchristo deleted the clevinson/buy-sell-msg-server branch November 15, 2021 18:43
@ryanchristo ryanchristo mentioned this pull request Nov 15, 2021
19 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add proto types definitions and msg server implementation for ecocredit marketplace functionality
5 participants