Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions proto/neutron/dex/limit_order_tranche_user.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ message LimitOrderTrancheUser {
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "shares_owned"
];

// DEPRECATED: shares_withdrawn will be removed in a future release, `dec_shares_withdrawn` should be used
string shares_withdrawn = 6 [
deprecated = true,
(gogoproto.moretags) = "yaml:\"shares_withdrawn\"",
(gogoproto.customtype) = "cosmossdk.io/math.Int",
(gogoproto.nullable) = false,
Expand All @@ -32,4 +35,10 @@ message LimitOrderTrancheUser {
(gogoproto.jsontag) = "shares_cancelled"
];
LimitOrderType order_type = 8;
string dec_shares_withdrawn = 9 [
(gogoproto.moretags) = "yaml:\"dec_shares_withdrawn\"",
(gogoproto.customtype) = "github.com/neutron-org/neutron/v10/utils/math.PrecDec",
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "dec_shares_withdrawn"
];
}
6 changes: 4 additions & 2 deletions tests/dex/state_withdraw_limit_order_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,10 @@ func (s *DexStateTestSuite) assertWithdrawFilledAmount(params withdrawLimitOrder
s.False(found)
} else {
s.True(found)
remainingShares := ut.SharesOwned.Sub(ut.SharesWithdrawn)
s.True(expectedBalanceA.Equal(remainingShares), "Expected Balance A %v != Actual %v", expectedBalanceA, remainingShares)
sharesOwnedDec := math_utils.NewPrecDecFromInt(ut.SharesOwned)
remainingShares := sharesOwnedDec.Sub(ut.DecSharesWithdrawn)
expectedBalanceADec := math_utils.NewPrecDecFromInt(expectedBalanceA)
s.True(expectedBalanceADec.Equal(remainingShares), "Expected Balance A %v != Actual %v", expectedBalanceA, remainingShares)
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions x/dex/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/neutron-org/neutron/v10/testutil/common/nullify"
keepertest "github.com/neutron-org/neutron/v10/testutil/dex/keeper"
math_utils "github.com/neutron-org/neutron/v10/utils/math"
"github.com/neutron-org/neutron/v10/x/dex"
"github.com/neutron-org/neutron/v10/x/dex/types"
)
Expand All @@ -26,7 +27,7 @@ func TestGenesis(t *testing.T) {
TrancheKey: "0",
Address: "fakeAddr",
SharesOwned: math.NewInt(10),
SharesWithdrawn: math.NewInt(0),
DecSharesWithdrawn: math_utils.ZeroPrecDec(),
},
{
TradePairId: &types.TradePairID{
Expand All @@ -37,7 +38,7 @@ func TestGenesis(t *testing.T) {
TrancheKey: "0",
Address: "fakeAddr",
SharesOwned: math.NewInt(10),
SharesWithdrawn: math.NewInt(0),
DecSharesWithdrawn: math_utils.ZeroPrecDec(),
},
},
TickLiquidityList: []*types.TickLiquidity{
Expand Down
6 changes: 3 additions & 3 deletions x/dex/keeper/cancel_limit_order.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ func (k Keeper) ExecuteCancelLimitOrder(
tranche.TotalMakerDenom = tranche.TotalMakerDenom.Sub(trancheUser.SharesOwned)

// Calculate total number of shares removed previously withdrawn by the user (denominated in takerDenom)
sharesWithdrawnTakerDenom := math_utils.NewPrecDecFromInt(trancheUser.SharesWithdrawn).
Quo(tranche.PriceTakerToMaker)
sharesWithdrawnTakerDenom := trancheUser.DecSharesWithdrawn.
Mul(tranche.MakerPrice)

// Calculate the total amount removed including prior withdrawals (denominated in takerDenom)
totalAmountOutTakerDenom := sharesWithdrawnTakerDenom.Add(takerAmountOut)
Expand All @@ -101,7 +101,7 @@ func (k Keeper) ExecuteCancelLimitOrder(
tranche.SetTotalTakerDenom(tranche.DecTotalTakerDenom.Sub(totalAmountOutTakerDenom))

// Set TrancheUser to 100% shares withdrawn
trancheUser.SharesWithdrawn = trancheUser.SharesOwned
trancheUser.SetSharesWithdrawn(math_utils.NewPrecDecFromInt(trancheUser.SharesOwned))

if !makerAmountToReturn.IsPositive() && !takerAmountOut.IsPositive() {
return types.PrecDecCoin{}, types.PrecDecCoin{}, sdkerrors.Wrapf(types.ErrCancelEmptyLimitOrder, "%s", tranche.Key.TrancheKey)
Expand Down
9 changes: 5 additions & 4 deletions x/dex/keeper/grpc_query_limit_order_tranche_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ package keeper
import (
"context"

"cosmossdk.io/math"
"cosmossdk.io/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

math_utils "github.com/neutron-org/neutron/v10/utils/math"
"github.com/neutron-org/neutron/v10/x/dex/types"
)

Expand Down Expand Up @@ -47,7 +47,7 @@ func (k Keeper) LimitOrderTrancheUserAll(
}, nil
}

func (k Keeper) CalcWithdrawableShares(ctx sdk.Context, trancheUser types.LimitOrderTrancheUser) (amount math.Int, err error) {
func (k Keeper) CalcWithdrawableShares(ctx sdk.Context, trancheUser types.LimitOrderTrancheUser) (amount math_utils.PrecDec, err error) {
tradePairID, tickIndex := trancheUser.TradePairId, trancheUser.TickIndexTakerToMaker

tranche, _, found := k.FindLimitOrderTranche(
Expand All @@ -60,7 +60,7 @@ func (k Keeper) CalcWithdrawableShares(ctx sdk.Context, trancheUser types.LimitO
)

if !found {
return math.ZeroInt(), status.Error(codes.NotFound, "Tranche not found")
return math_utils.ZeroPrecDec(), status.Error(codes.NotFound, "Tranche not found")
}
withdrawableShares, _ := tranche.CalcWithdrawAmount(&trancheUser)

Expand Down Expand Up @@ -89,7 +89,8 @@ func (k Keeper) LimitOrderTrancheUser(c context.Context,
if err != nil {
return nil, err
}
resp.WithdrawableShares = &withdrawAmt
withdrawAmtInt := withdrawAmt.TruncateInt()
resp.WithdrawableShares = &withdrawAmtInt
}

return resp, nil
Expand Down
52 changes: 50 additions & 2 deletions x/dex/keeper/integration_cancellimitorder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -532,9 +532,9 @@ func (s *DexTestSuite) TestWithdrawThenCancelLowTick() {
s.assertAliceBalancesInt(sdkmath.NewInt(13058413), sdkmath.NewInt(4999999))

s.bobWithdrawsLimitSell(trancheKey)
s.assertBobBalancesInt(sdkmath.ZeroInt(), sdkmath.NewInt(4999999))
s.assertBobBalances(0, 5)
s.bobCancelsLimitSell(trancheKey)
s.assertBobBalancesInt(sdkmath.NewInt(13058413), sdkmath.NewInt(4999999))
s.assertBobBalancesInt(sdkmath.NewInt(13058413), sdkmath.NewInt(5_000_000))
}

func (s *DexTestSuite) TestWrongSharesProtectionCancel() {
Expand All @@ -553,3 +553,51 @@ func (s *DexTestSuite) TestWrongSharesProtectionCancel() {

s.assertAliceBalances(1, 0)
}

func (s *DexTestSuite) TestCanceLimitOrderClearsPosition() {
s.fundAccountBalancesInt(s.alice, sdkmath.NewInt(10_000), sdkmath.ZeroInt())
s.fundAccountBalancesInt(s.bob, sdkmath.NewInt(500_000), sdkmath.ZeroInt())
s.fundAccountBalancesInt(s.carol, sdkmath.ZeroInt(), sdkmath.NewInt(22_015))

// GIVEN alice and bob place GTC limit sells at tick -100000
trancheKey := s.limitSellsIntSuccess(s.alice, "TokenA", -100000, sdkmath.NewInt(10_000))
s.limitSellsIntSuccess(s.bob, "TokenA", -100000, sdkmath.NewInt(500_000))

// AND carol swaps 22,015 TokenB for TokeA
s.limitSellsIntSuccess(s.carol, "TokenB", -100001, sdkmath.NewInt(22_015), types.LimitOrderType_FILL_OR_KILL)

// WHEN Alice withdraws then cancels
s.aliceWithdrawsLimitSell(trancheKey)
s.aliceCancelsLimitSell(trancheKey)

// THEN totalTakerDenom == ReservesTakerDenom
tranche, _, found := s.App.DexKeeper.FindLimitOrderTranche(
s.Ctx,
&types.LimitOrderTrancheKey{
TradePairId: types.MustNewTradePairID("TokenB", "TokenA"),
TickIndexTakerToMaker: 100000,
TrancheKey: trancheKey,
},
)
s.True(found)

s.Equal(tranche.DecTotalTakerDenom, tranche.DecReservesTakerDenom)

// WHEN bob cancels his limit order, the tranche only contains dust
s.bobCancelsLimitSell(trancheKey)

// Final tranche state
tranche, _, found = s.App.DexKeeper.FindLimitOrderTranche(
s.Ctx,
&types.LimitOrderTrancheKey{
TradePairId: types.MustNewTradePairID("TokenB", "TokenA"),
TickIndexTakerToMaker: 100000,
TrancheKey: trancheKey,
},
)
s.True(found)

// NOTE: we are using the Int fields just to ensure only dust is left
s.Assert().Equal(tranche.ReservesTakerDenom, sdkmath.ZeroInt())
s.Assert().Equal(tranche.TotalTakerDenom, sdkmath.ZeroInt())
}
2 changes: 2 additions & 0 deletions x/dex/keeper/limit_order_tranche_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"

math_utils "github.com/neutron-org/neutron/v10/utils/math"
"github.com/neutron-org/neutron/v10/x/dex/types"
)

Expand All @@ -33,6 +34,7 @@ func (k Keeper) GetOrInitLimitOrderTrancheUser(
Address: receiver,
SharesOwned: math.ZeroInt(),
SharesWithdrawn: math.ZeroInt(),
DecSharesWithdrawn: math_utils.ZeroPrecDec(),
TickIndexTakerToMaker: tickIndex,
TradePairId: tradePairID,
OrderType: orderType,
Expand Down
11 changes: 7 additions & 4 deletions x/dex/keeper/limit_order_tranche_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/neutron-org/neutron/v10/testutil/common/nullify"
keepertest "github.com/neutron-org/neutron/v10/testutil/dex/keeper"
math_utils "github.com/neutron-org/neutron/v10/utils/math"
"github.com/neutron-org/neutron/v10/x/dex/keeper"
"github.com/neutron-org/neutron/v10/x/dex/types"
)
Expand All @@ -24,7 +25,7 @@ func createNLimitOrderTrancheUser(keeper *keeper.Keeper, ctx sdk.Context, n int)
TradePairId: &types.TradePairID{MakerDenom: "TokenA", TakerDenom: "TokenB"},
TickIndexTakerToMaker: int64(i),
SharesOwned: math.NewInt(100),
SharesWithdrawn: math.ZeroInt(),
DecSharesWithdrawn: math_utils.ZeroPrecDec(),
}
items[i] = val
keeper.SetLimitOrderTrancheUser(ctx, items[i])
Expand All @@ -42,7 +43,7 @@ func createNLimitOrderTrancheUserWithAddress(keeper *keeper.Keeper, ctx sdk.Cont
TradePairId: &types.TradePairID{MakerDenom: "TokenA", TakerDenom: "TokenB"},
TickIndexTakerToMaker: 0,
SharesOwned: math.ZeroInt(),
SharesWithdrawn: math.ZeroInt(),
DecSharesWithdrawn: math_utils.ZeroPrecDec(),
}
items[i] = val
keeper.SetLimitOrderTrancheUser(ctx, items[i])
Expand Down Expand Up @@ -91,7 +92,8 @@ func (s *DexTestSuite) TestGetAllLimitOrders() {
TrancheKey: trancheKeyA,
Address: s.alice.String(),
SharesOwned: math.NewInt(10_000_000),
SharesWithdrawn: math.NewInt(0),
SharesWithdrawn: math.ZeroInt(),
DecSharesWithdrawn: math_utils.ZeroPrecDec(),
SharesCancelled: math.ZeroInt(),
},
LOList[0],
Expand All @@ -102,7 +104,8 @@ func (s *DexTestSuite) TestGetAllLimitOrders() {
TrancheKey: trancheKeyB,
Address: s.alice.String(),
SharesOwned: math.NewInt(10_000_000),
SharesWithdrawn: math.NewInt(0),
SharesWithdrawn: math.ZeroInt(),
DecSharesWithdrawn: math_utils.ZeroPrecDec(),
SharesCancelled: math.ZeroInt(),
},
LOList[1],
Expand Down
6 changes: 6 additions & 0 deletions x/dex/keeper/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
v4 "github.com/neutron-org/neutron/v10/x/dex/migrations/v4"
v5 "github.com/neutron-org/neutron/v10/x/dex/migrations/v5"
v6 "github.com/neutron-org/neutron/v10/x/dex/migrations/v6"
v7 "github.com/neutron-org/neutron/v10/x/dex/migrations/v7"
)

// Migrator is a struct for handling in-place store migrations.
Expand Down Expand Up @@ -38,3 +39,8 @@ func (m Migrator) Migrate4to5(ctx sdk.Context) error {
func (m Migrator) Migrate5to6(ctx sdk.Context) error {
return v6.MigrateStore(ctx, m.keeper.cdc, m.keeper.storeKey)
}

// Migrate6to7 migrates from version 6 to 7.
func (m Migrator) Migrate6to7(ctx sdk.Context) error {
return v7.MigrateStore(ctx, m.keeper.cdc, m.keeper.storeKey)
}
8 changes: 4 additions & 4 deletions x/dex/keeper/withdraw_filled_limit_order.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"

sdkerrors "cosmossdk.io/errors"
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"

math_utils "github.com/neutron-org/neutron/v10/utils/math"
Expand Down Expand Up @@ -82,7 +81,7 @@ func (k Keeper) ExecuteWithdrawFilledLimitOrder(
remainingTokenIn := math_utils.ZeroPrecDec()
// It's possible that a TrancheUser exists but tranche does not if LO was filled entirely through a swap
if found {
var amountOutTokenIn math.Int
var amountOutTokenIn math_utils.PrecDec
amountOutTokenIn, amountOutTokenOut, err = tranche.Withdraw(trancheUser)
if err != nil {
return types.PrecDecCoin{}, types.PrecDecCoin{}, err
Expand All @@ -97,12 +96,13 @@ func (k Keeper) ExecuteWithdrawFilledLimitOrder(
k.UpdateInactiveTranche(ctx, tranche)

// Since the order has already been filled we treat this as a complete withdrawal
trancheUser.SharesWithdrawn = trancheUser.SharesOwned
trancheUser.SetSharesWithdrawn(math_utils.NewPrecDecFromInt(trancheUser.SharesOwned))

} else {
// This was an active tranche (still has MakerReserves) and we have only removed TakerReserves; we will save it as an active tranche
k.UpdateTranche(ctx, tranche)
trancheUser.SharesWithdrawn = trancheUser.SharesWithdrawn.Add(amountOutTokenIn)
totalSharesWithdrawn := trancheUser.DecSharesWithdrawn.Add(amountOutTokenIn)
trancheUser.SetSharesWithdrawn(totalSharesWithdrawn)
}

}
Expand Down
61 changes: 61 additions & 0 deletions x/dex/migrations/v7/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package v6
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess it should be v7?


import (
errorsmod "cosmossdk.io/errors"
"cosmossdk.io/store/prefix"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"

math_utils "github.com/neutron-org/neutron/v10/utils/math"
"github.com/neutron-org/neutron/v10/x/dex/types"
)

// MigrateStore performs in-place store migrations.
// Add DecSharesWithdrawn field to all LimitOrderTrancheUser
func MigrateStore(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error {
if err := migrateLimitOrderTrancheUsers(ctx, cdc, storeKey); err != nil {
return err
}

return nil
}

type migrationUpdate struct {
key []byte
val []byte
}

func migrateLimitOrderTrancheUsers(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error {
ctx.Logger().Info("Migrating LimitOrderTrancheUser fields...")

// Iterate through all LimitOrderTrancheUser
store := prefix.NewStore(ctx.KVStore(storeKey), types.KeyPrefix(types.LimitOrderTrancheUserKeyPrefix))
iterator := storetypes.KVStorePrefixIterator(store, []byte{})
trancheUserUpdates := make([]migrationUpdate, 0)

for ; iterator.Valid(); iterator.Next() {
var limitOrderTrancheUser types.LimitOrderTrancheUser
cdc.MustUnmarshal(iterator.Value(), &limitOrderTrancheUser)

limitOrderTrancheUser.DecSharesWithdrawn = math_utils.NewPrecDecFromInt(limitOrderTrancheUser.SharesWithdrawn)

bz := cdc.MustMarshal(&limitOrderTrancheUser)
trancheUserUpdates = append(trancheUserUpdates, migrationUpdate{key: iterator.Key(), val: bz})

}

err := iterator.Close()
if err != nil {
return errorsmod.Wrap(err, "iterator failed to close during migration")
}

// Store the updated LimitOrderTrancheUser
for _, v := range trancheUserUpdates {
store.Set(v.key, v.val)
}

ctx.Logger().Info("Finished migrating LimitOrderTrancheUser fields...")

return nil
}
Loading
Loading