-
Notifications
You must be signed in to change notification settings - Fork 102
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: fix estimateXX dex queries #NTRN-318 #543
Changes from all commits
e3ac929
33b5549
9083cde
8ff24d2
cf0ccf6
fe1ab28
fcf9feb
4d67e6f
d236ce9
4d540e1
8a9aed7
ffcec4f
cd8d9e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package keeper_test | ||
|
||
import ( | ||
"cosmossdk.io/math" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
|
||
"github.com/neutron-org/neutron/v4/x/dex/types" | ||
) | ||
|
||
func (s *DexTestSuite) TestEstimatePlaceLimitOrderGTC() { | ||
// GIVEN liquidity A<>B | ||
s.SetupMultiplePools( | ||
NewPoolSetup("TokenA", "TokenB", 0, 1, 0, 1), | ||
NewPoolSetup("TokenA", "TokenB", 0, 1, 1, 1), | ||
) | ||
|
||
// WHEN estimate GTC Limit order selling "TokenA" | ||
resp, err := s.App.DexKeeper.EstimatePlaceLimitOrder(s.Ctx, &types.QueryEstimatePlaceLimitOrderRequest{ | ||
TokenIn: "TokenA", | ||
TokenOut: "TokenB", | ||
TickIndexInToOut: 4, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's out of scope of the pr, but message QueryEstimatePlaceLimitOrderRequest {
MsgPlaceLimitOrder msg = 1;
} to not copypaste whole bunch of fields. The only downside i can see you can get rid of |
||
AmountIn: math.NewInt(3_000_000), | ||
OrderType: types.LimitOrderType_GOOD_TIL_CANCELLED, | ||
}) | ||
s.NoError(err) | ||
|
||
// Then estimate is 3 BIG TokenA in with 2 BIG TokenB out from swap | ||
s.True(math.NewInt(3_000_000).Equal(resp.TotalInCoin.Amount), "Got %v", resp.TotalInCoin.Amount) | ||
s.Equal("TokenA", resp.TotalInCoin.Denom) | ||
|
||
s.True(math.NewInt(2_000_301).Equal(resp.SwapInCoin.Amount), "Got %v", resp.SwapInCoin.Amount) | ||
s.Equal("TokenA", resp.SwapInCoin.Denom) | ||
|
||
s.True(math.NewInt(2_000_000).Equal(resp.SwapOutCoin.Amount), "Got %v", resp.SwapOutCoin.Amount) | ||
s.Equal("TokenB", resp.SwapOutCoin.Denom) | ||
|
||
// AND state is not altered | ||
s.assertDexBalanceWithDenom("TokenA", 0) | ||
s.assertDexBalanceWithDenom("TokenB", 2) | ||
|
||
// No events are emitted | ||
s.AssertEventValueNotEmitted(types.TickUpdateEventKey, "Expected no events") | ||
|
||
// Subsequent transactions use the original BankKeeper | ||
// ie. The simulation bankkeeper is not retained giving users unlimited funds | ||
s.assertBobLimitSellFails(sdkerrors.ErrInsufficientFunds, "TokenA", -400_000, 100_000_000) | ||
} | ||
|
||
func (s *DexTestSuite) TestEstimatePlaceLimitOrderFoK() { | ||
// GIVEN liquidity TokenB | ||
s.SetupMultiplePools( | ||
NewPoolSetup("TokenA", "TokenB", 0, 1, 0, 1), | ||
NewPoolSetup("TokenA", "TokenB", 0, 1, 1, 1), | ||
) | ||
|
||
// WHEN estimate FoK Limit order selling "TokenA" | ||
resp, err := s.App.DexKeeper.EstimatePlaceLimitOrder(s.Ctx, &types.QueryEstimatePlaceLimitOrderRequest{ | ||
TokenIn: "TokenA", | ||
TokenOut: "TokenB", | ||
TickIndexInToOut: 4, | ||
AmountIn: math.NewInt(1_500_000), | ||
OrderType: types.LimitOrderType_FILL_OR_KILL, | ||
}) | ||
s.NoError(err) | ||
|
||
// Then estimate is 1.5 BIG TokenA in with 1.5 BIG TokenB out from swap | ||
s.True(math.NewInt(1_500_000).Equal(resp.TotalInCoin.Amount), "Got %v", resp.TotalInCoin.Amount) | ||
s.Equal("TokenA", resp.TotalInCoin.Denom) | ||
|
||
s.True(math.NewInt(1_500_000).Equal(resp.SwapInCoin.Amount), "Got %v", resp.SwapInCoin.Amount) | ||
s.Equal("TokenA", resp.SwapInCoin.Denom) | ||
|
||
s.True(math.NewInt(1_499_800).Equal(resp.SwapOutCoin.Amount), "Got %v", resp.SwapOutCoin.Amount) | ||
s.Equal("TokenB", resp.SwapOutCoin.Denom) | ||
|
||
// AND state is not altered | ||
s.assertDexBalanceWithDenom("TokenA", 0) | ||
s.assertDexBalanceWithDenom("TokenB", 2) | ||
|
||
// No events are emitted | ||
s.AssertEventValueNotEmitted(types.TickUpdateEventKey, "Expected no events") | ||
|
||
// Subsequent transactions use the original BankKeeper | ||
s.assertBobLimitSellFails(sdkerrors.ErrInsufficientFunds, "TokenA", -400_000, 100_000_000) | ||
} | ||
|
||
func (s *DexTestSuite) TestEstimatePlaceLimitOrderFoKFails() { | ||
// GIVEN no liquidity | ||
|
||
// WHEN estimate placeLimitOrder | ||
resp, err := s.App.DexKeeper.EstimatePlaceLimitOrder(s.Ctx, &types.QueryEstimatePlaceLimitOrderRequest{ | ||
TokenIn: "TokenA", | ||
TokenOut: "TokenB", | ||
TickIndexInToOut: 4, | ||
AmountIn: math.NewInt(1_500_000), | ||
OrderType: types.LimitOrderType_IMMEDIATE_OR_CANCEL, | ||
}) | ||
|
||
// THEN error is returned | ||
s.ErrorIs(err, types.ErrLimitPriceNotSatisfied) | ||
s.Nil(resp) | ||
|
||
// Subsequent transactions use the original BankKeeper | ||
s.assertBobLimitSellFails(sdkerrors.ErrInsufficientFunds, "TokenA", -400_000, 100_000_000) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,14 +8,14 @@ import ( | |
"github.com/neutron-org/neutron/v4/x/dex/types" | ||
) | ||
|
||
// TODO: This doesn't run ValidateBasic() checks. | ||
func (k Keeper) EstimateMultiHopSwap( | ||
goCtx context.Context, | ||
req *types.QueryEstimateMultiHopSwapRequest, | ||
) (*types.QueryEstimateMultiHopSwapResponse, error) { | ||
msg := types.MsgMultiHopSwap{ | ||
Creator: req.Creator, | ||
Receiver: req.Receiver, | ||
// Add a random address so that Validate passes. This address is not used for anything within the query | ||
Creator: "neutron1dft8nwxzr0u27wvr2cknpermjkreqvp9fdy0uz", | ||
Receiver: "neutron1dft8nwxzr0u27wvr2cknpermjkreqvp9fdy0uz", | ||
Comment on lines
+17
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this address? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a random valid address. Will add a comment. But let me know if there's a more preferable way to do this. I agree it's a bit odd. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably need to create another message |
||
Routes: req.Routes, | ||
AmountIn: req.AmountIn, | ||
ExitLimitPrice: req.ExitLimitPrice, | ||
|
@@ -28,23 +28,16 @@ func (k Keeper) EstimateMultiHopSwap( | |
ctx := sdk.UnwrapSDKContext(goCtx) | ||
cacheCtx, _ := ctx.CacheContext() | ||
|
||
callerAddr := sdk.MustAccAddressFromBech32(req.Creator) | ||
receiverAddr := sdk.MustAccAddressFromBech32(req.Receiver) | ||
|
||
coinOut, err := k.MultiHopSwapCore( | ||
bestRoute, _, err := k.CalulateMultiHopSwap( | ||
cacheCtx, | ||
req.AmountIn, | ||
req.Routes, | ||
req.ExitLimitPrice, | ||
req.PickBestRoute, | ||
callerAddr, | ||
receiverAddr, | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// NB: Critically, we do not write the best route's buffered state context since this is only an estimate. | ||
|
||
return &types.QueryEstimateMultiHopSwapResponse{CoinOut: coinOut}, nil | ||
return &types.QueryEstimateMultiHopSwapResponse{CoinOut: bestRoute.coinOut}, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets rename the file to grpc_query_estimate_place_limit_order_test to get exact before grpc_query_estimate_place_limit_order.go in listing