Skip to content

Commit

Permalink
test for CalculateResultExactAmountIn and CalculateResultExactAmountOut
Browse files Browse the repository at this point in the history
  • Loading branch information
jununifi committed Jul 10, 2024
1 parent d3f372f commit ea89a9f
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 11 deletions.
4 changes: 2 additions & 2 deletions x/liquiditypool/keeper/msg_server_position.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,12 +310,12 @@ func (k Keeper) resetPool(ctx sdk.Context, pool types.Pool) {
}

func (k Keeper) UpdatePosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, lowerTick, upperTick int64, liquidityDelta math.LegacyDec, positionId uint64) (amountBase math.Int, amountQuote math.Int, lowerTickEmpty bool, upperTickEmpty bool, err error) {
lowerTickIsEmpty, err := k.initOrUpdateTick(ctx, poolId, lowerTick, liquidityDelta, false)
lowerTickIsEmpty, err := k.UpsertTick(ctx, poolId, lowerTick, liquidityDelta, false)
if err != nil {
return math.Int{}, math.Int{}, false, false, err
}

upperTickIsEmpty, err := k.initOrUpdateTick(ctx, poolId, upperTick, liquidityDelta, true)
upperTickIsEmpty, err := k.UpsertTick(ctx, poolId, upperTick, liquidityDelta, true)
if err != nil {
return math.Int{}, math.Int{}, false, false, err
}
Expand Down
6 changes: 3 additions & 3 deletions x/liquiditypool/keeper/swap.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,13 +458,13 @@ func (k Keeper) swapCrossTickLogic(ctx sdk.Context,
denomIn string,
updateAccumulators bool,
) (SwapState, error) {
nextInitializedTickInfo, err := ParseTickFromBz(nextTickIter.Value())
nextInitializedTickInfo, err := DecodeTickBytes(nextTickIter.Value())
if err != nil {
return swapState, err
}
if updateAccumulators {
feeGrowth := sdk.DecCoin{Denom: denomIn, Amount: swapState.globalFeeGrowthPerUnitLiquidity}
err := k.crossTick(ctx, p.Id, nextInitializedTick, &nextInitializedTickInfo, feeGrowth, feeAccumulator.AccumValue)
err := k.CrossTick(ctx, p.Id, nextInitializedTick, &nextInitializedTickInfo, feeGrowth, feeAccumulator.AccumValue)
if err != nil {
return swapState, err
}
Expand Down Expand Up @@ -652,7 +652,7 @@ func (k Keeper) ComputeMaxInAmtGivenMaxTicksCrossed(
totalTokenOut = totalTokenOut.Add(amountOut)

if nextInitializedTickSqrtPrice.Equal(computedSqrtPrice) {
nextInitializedTickInfo, err := ParseTickFromBz(nextInitTickIter.Value())
nextInitializedTickInfo, err := DecodeTickBytes(nextInitTickIter.Value())
if err != nil {
return sdk.Coin{}, sdk.Coin{}, err
}
Expand Down
234 changes: 228 additions & 6 deletions x/liquiditypool/keeper/swap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import (
// TODO: add test for updateFeeGrowthGlobal
// TODO: add test for swapOutAmtGivenIn
// TODO: add test for swapInAmtGivenOut
// TODO: add test for CalculateResultExactAmountIn
// TODO: add test for CalculateResultExactAmountOut
// TODO: add test for iteratorToNextTickSqrtPriceTarget
// TODO: add test for computeOutAmtGivenIn
// TODO: add test for computeInAmtGivenOut
Expand Down Expand Up @@ -331,15 +329,15 @@ func TestSwapExactAmountOut_SinglePosition(t *testing.T) {
pool, found := k.GetPool(ctx, 1)
require.True(t, found)

amountOut, err := k.SwapExactAmountOut(wctx, sender, pool, tc.tokenOut, tc.denomIn, tc.feeEnabled)
amountIn, err := k.SwapExactAmountOut(wctx, sender, pool, tc.tokenOut, tc.denomIn, tc.feeEnabled)
if tc.err != nil {
require.ErrorIs(t, err, tc.err)
} else {
require.NoError(t, err)

pool, found := k.GetPool(ctx, 1)
require.True(t, found)
require.Equal(t, amountOut.String(), tc.expAmountIn.String())
require.Equal(t, amountIn.String(), tc.expAmountIn.String())
require.Equal(t, pool.CurrentTick, tc.expTickIndex)
}
})
Expand Down Expand Up @@ -419,12 +417,12 @@ func TestSwapExactAmountOut_MultiplePositions(t *testing.T) {
pool, found := k.GetPool(ctx, 1)
require.True(t, found)

amountOut, err := k.SwapExactAmountOut(wctx, sender, pool, tc.tokenOut, tc.denomIn, tc.feeEnabled)
amountIn, err := k.SwapExactAmountOut(wctx, sender, pool, tc.tokenOut, tc.denomIn, tc.feeEnabled)
if tc.err != nil {
require.ErrorIs(t, err, tc.err)
} else {
require.NoError(t, err)
require.Equal(t, amountOut.String(), tc.expAmountIn.String())
require.Equal(t, amountIn.String(), tc.expAmountIn.String())

pool, found := k.GetPool(ctx, 1)
require.True(t, found)
Expand Down Expand Up @@ -474,3 +472,227 @@ func TestGetValidatedPoolAndAccumulator(t *testing.T) {
_, _, err = k.GetValidatedPoolAndAccumulator(ctx, 1, "invalid_denom", "quote")
require.Error(t, err)
}

func TestCalculateResultExactAmountOut(t *testing.T) {
sender := sdk.AccAddress("sender")

tests := []struct {
desc string
tokenOut sdk.Coin
denomIn string
feeEnabled bool
expAmountIn math.Int
expTickIndex int64
err error
}{
{
desc: "Base to quote",
tokenOut: sdk.NewInt64Coin("base", 100000),
denomIn: "quote",
feeEnabled: false,
expAmountIn: math.NewInt(100006),
expTickIndex: 0,
},
{
desc: "Quote to base",
tokenOut: sdk.NewInt64Coin("base", 100000),
denomIn: "quote",
feeEnabled: false,
expAmountIn: math.NewInt(100006),
expTickIndex: 0,
},
{
desc: "Fee enabled",
tokenOut: sdk.NewInt64Coin("base", 100000),
denomIn: "quote",
feeEnabled: true,
expAmountIn: math.NewInt(101017),
expTickIndex: 0,
},
{
desc: "Ran out of ticks",
tokenOut: sdk.NewInt64Coin("base", 1000000000),
denomIn: "quote",
feeEnabled: true,
err: types.ErrRanOutOfTicks,
},
{
desc: "Empty token in",
tokenOut: sdk.NewInt64Coin("base", 0),
denomIn: "quote",
feeEnabled: true,
expAmountIn: math.NewInt(0),
err: nil,
},
{
desc: "same token in and out",
tokenOut: sdk.NewInt64Coin("base", 0),
denomIn: "base",
feeEnabled: true,
expAmountIn: math.NewInt(100000),
err: types.ErrDenomDuplication,
},
{
desc: "invalid denomIn",
tokenOut: sdk.NewInt64Coin("base", 0),
denomIn: "invalid",
feeEnabled: true,
expAmountIn: math.NewInt(100000),
err: types.ErrInvalidInDenom,
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
k, bk, srv, ctx := setupMsgServer(t)
wctx := sdk.UnwrapSDKContext(ctx)

bk.EXPECT().IsSendEnabledCoins(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
bk.EXPECT().SendCoins(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()

_, err := srv.CreatePool(wctx, &types.MsgCreatePool{
Authority: sender.String(),
DenomBase: "base",
DenomQuote: "quote",
FeeRate: "0.01",
PriceRatio: "1.0001",
BaseOffset: "0.5",
})
require.NoError(t, err)

_, err = srv.CreatePosition(wctx, &types.MsgCreatePosition{
Sender: sender.String(),
PoolId: 1,
LowerTick: -10,
UpperTick: 10,
TokenBase: sdk.NewInt64Coin("base", 1000000),
TokenQuote: sdk.NewInt64Coin("quote", 1000000),
MinAmountBase: math.NewInt(0),
MinAmountQuote: math.NewInt(0),
})
require.NoError(t, err)

pool, found := k.GetPool(ctx, 1)
require.True(t, found)

amountIn, err := k.CalculateResultExactAmountOut(wctx, pool, tc.tokenOut, tc.denomIn, tc.feeEnabled)
if tc.err != nil {
require.Error(t, err, tc.err)
} else {
require.NoError(t, err)
require.Equal(t, amountIn.String(), tc.expAmountIn.String())
}
})
}
}

func TestCalculateResultExactAmountIn(t *testing.T) {
sender := sdk.AccAddress("sender")

tests := []struct {
desc string
tokenIn sdk.Coin
denomOut string
feeEnabled bool
expAmountOut math.Int
expTickIndex int64
err error
}{
{
desc: "Base to quote",
tokenIn: sdk.NewInt64Coin("base", 100000),
denomOut: "quote",
feeEnabled: false,
expAmountOut: math.NewInt(99994),
expTickIndex: -2,
},
{
desc: "Quote to base",
tokenIn: sdk.NewInt64Coin("base", 100000),
denomOut: "quote",
feeEnabled: false,
expAmountOut: math.NewInt(99994),
expTickIndex: -2,
},
{
desc: "Fee enabled",
tokenIn: sdk.NewInt64Coin("base", 100000),
denomOut: "quote",
feeEnabled: true,
expAmountOut: math.NewInt(98994),
expTickIndex: -2,
},
{
desc: "Ran out of ticks",
tokenIn: sdk.NewInt64Coin("base", 1000000000),
denomOut: "quote",
feeEnabled: true,
err: types.ErrRanOutOfTicks,
},
{
desc: "Empty token in",
tokenIn: sdk.NewInt64Coin("base", 0),
denomOut: "quote",
feeEnabled: true,
expAmountOut: math.NewInt(0),
err: nil,
},
{
desc: "same token in and out",
tokenIn: sdk.NewInt64Coin("base", 0),
denomOut: "base",
feeEnabled: true,
expAmountOut: math.NewInt(100000),
err: types.ErrDenomDuplication,
},
{
desc: "invalid denomOut",
tokenIn: sdk.NewInt64Coin("base", 0),
denomOut: "invalid",
feeEnabled: true,
expAmountOut: math.NewInt(100000),
err: types.ErrInvalidOutDenom,
},
}
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
k, bk, srv, ctx := setupMsgServer(t)
wctx := sdk.UnwrapSDKContext(ctx)

bk.EXPECT().IsSendEnabledCoins(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
bk.EXPECT().SendCoins(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()

_, err := srv.CreatePool(wctx, &types.MsgCreatePool{
Authority: sender.String(),
DenomBase: "base",
DenomQuote: "quote",
FeeRate: "0.01",
PriceRatio: "1.0001",
BaseOffset: "0.5",
})
require.NoError(t, err)

_, err = srv.CreatePosition(wctx, &types.MsgCreatePosition{
Sender: sender.String(),
PoolId: 1,
LowerTick: -10,
UpperTick: 10,
TokenBase: sdk.NewInt64Coin("base", 1000000),
TokenQuote: sdk.NewInt64Coin("quote", 1000000),
MinAmountBase: math.NewInt(0),
MinAmountQuote: math.NewInt(0),
})
require.NoError(t, err)

pool, found := k.GetPool(ctx, 1)
require.True(t, found)

amountOut, err := k.CalculateResultExactAmountIn(wctx, pool, tc.tokenIn, tc.denomOut, tc.feeEnabled)
if tc.err != nil {
require.ErrorIs(t, err, tc.err)
} else {
require.NoError(t, err)
require.Equal(t, amountOut.String(), tc.expAmountOut.String())
}
})
}
}
1 change: 1 addition & 0 deletions x/liquiditypool/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,5 @@ var (
ErrZeroShares = sdkerrors.Register(ModuleName, 1137, "zero shares")
ErrAccumDoesNotExist = sdkerrors.Register(ModuleName, 1138, "accumulator does not exist")
ErrNegRewardAddition = sdkerrors.Register(ModuleName, 1139, "negative reward addition")
ErrTickNotFound = sdkerrors.Register(ModuleName, 1140, "tick not found")
)

0 comments on commit ea89a9f

Please sign in to comment.