From 29e69007ac56cd3ded7a3cb7535c7f83b3901d97 Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Mon, 18 Dec 2023 22:42:45 +0100 Subject: [PATCH] fix: fees does not require additional funds (#1718) * remove unused param * error rounding 1 cent * fix more code * add fee payment on close partially * temp commit! * last test upgrade * Update changelog * Update CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * ci(codecov.yml): set fixed patch target * ci: PR template too long --------- Co-authored-by: Unique Divine <51418232+Unique-Divine@users.noreply.github.com> Co-authored-by: Unique-Divine --- .github/codecov.yml | 3 + .github/pull_request_template.md | 11 +- CHANGELOG.md | 1 + x/perp/v2/client/cli/cli_test.go | 94 +++-- x/perp/v2/keeper/admin_test.go | 2 +- x/perp/v2/keeper/clearing_house.go | 50 ++- x/perp/v2/keeper/clearing_house_test.go | 535 ++++++++++-------------- x/perp/v2/keeper/margin_test.go | 84 ++-- x/perp/v2/keeper/msg_server.go | 3 +- x/perp/v2/keeper/position.go | 1 + x/perp/v2/keeper/settlement.go | 4 +- x/perp/v2/keeper/settlement_test.go | 12 +- x/perp/v2/types/amm.go | 4 +- 13 files changed, 372 insertions(+), 432 deletions(-) diff --git a/.github/codecov.yml b/.github/codecov.yml index 73f60319f..5baa518e6 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -27,6 +27,9 @@ coverage: threshold: 1% # Allow coverage to drop by X%, posting a success status. # removed_code_behavior: Takes values [off, removals_only, adjust_base] removed_code_behavior: adjust_base + patch: + default: + target: 70% comment: # this is a top-level key layout: " diff, flags, files" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ae4278186..e7349fe6b 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,7 +1,8 @@ -# Description +# Purpose / Abstract -What does this PR do? - -# Purpose +- Closes #AAA -Why is this PR important? + diff --git a/CHANGELOG.md b/CHANGELOG.md index e1fb031e2..b67a19b05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [#1632](https://github.com/NibiruChain/nibiru/pull/1632) - feat(perp): Add settle position transaction * [#1573](https://github.com/NibiruChain/nibiru/pull/1573) - feat(perp): Close markets and compute settlement price * [#1705](https://github.com/NibiruChain/nibiru/pull/1705) - feat(perp): Add oracle pair to market object +* [#1718](https://github.com/NibiruChain/nibiru/pull/1718) - fix: fees does not require additional funds ### Non-breaking/Compatible Improvements diff --git a/x/perp/v2/client/cli/cli_test.go b/x/perp/v2/client/cli/cli_test.go index 90937d9fe..9113d95c7 100644 --- a/x/perp/v2/client/cli/cli_test.go +++ b/x/perp/v2/client/cli/cli_test.go @@ -244,8 +244,8 @@ func (s *IntegrationTestSuite) TestMarketOrdersAndCloseCmd() { ammMarketDuo, err = testutilcli.QueryMarketV2(val.ClientCtx, pair) s.Require().NoError(err) s.T().Logf("ammMarketDuo: %s", ammMarketDuo.String()) - s.EqualValues(sdk.MustNewDecFromStr("9999666.677777407419752675"), ammMarketDuo.Amm.BaseReserve) - s.EqualValues(sdk.MustNewDecFromStr("10000333.333333333333333333"), ammMarketDuo.Amm.QuoteReserve) + s.EqualValues(sdk.MustNewDecFromStr("9999667.344399676304101617"), ammMarketDuo.Amm.BaseReserve) + s.EqualValues(sdk.MustNewDecFromStr("10000332.666666666666666667"), ammMarketDuo.Amm.QuoteReserve) s.T().Log("B. check trader position") queryResp, err := testutilcli.QueryPositionV2(val.ClientCtx, asset.Registry.Pair(denoms.BTC, denoms.NUSD), user) @@ -253,11 +253,11 @@ func (s *IntegrationTestSuite) TestMarketOrdersAndCloseCmd() { s.T().Logf("query response: %+v", queryResp) s.EqualValues(user.String(), queryResp.Position.TraderAddress) s.EqualValues(asset.Registry.Pair(denoms.BTC, denoms.NUSD), queryResp.Position.Pair) - s.EqualValues(sdk.MustNewDecFromStr("333.322222592580247325"), queryResp.Position.Size_) - s.EqualValues(sdk.NewDec(2*common.TO_MICRO), queryResp.Position.Margin) - s.EqualValues(sdk.NewDec(2*common.TO_MICRO), queryResp.Position.OpenNotional) - s.EqualValues(sdk.MustNewDecFromStr("1999999.999999999999998000"), queryResp.PositionNotional) - s.EqualValues(sdk.MustNewDecFromStr("-0.000000000000002000"), queryResp.UnrealizedPnl) + s.EqualValues(sdk.MustNewDecFromStr("332.655600323695898383"), queryResp.Position.Size_) + s.EqualValues(sdk.MustNewDecFromStr("1996000.000000000000000000"), queryResp.Position.Margin) + s.EqualValues(sdk.MustNewDecFromStr("1996000.000000000000000000"), queryResp.Position.OpenNotional) + s.EqualValues(sdk.MustNewDecFromStr("1996000.000000000000002000"), queryResp.PositionNotional) + s.EqualValues(sdk.MustNewDecFromStr("0.000000000000002000"), queryResp.UnrealizedPnl) s.EqualValues(sdk.OneDec(), queryResp.MarginRatio) s.T().Log("C. open position with 2x leverage and zero baseAmtLimit") @@ -278,12 +278,12 @@ func (s *IntegrationTestSuite) TestMarketOrdersAndCloseCmd() { s.T().Logf("query response: %+v", queryResp) s.EqualValues(user.String(), queryResp.Position.TraderAddress) s.EqualValues(asset.Registry.Pair(denoms.BTC, denoms.NUSD), queryResp.Position.Pair) - s.EqualValues(sdk.MustNewDecFromStr("999.900009999000099990"), queryResp.Position.Size_) - s.EqualValues(sdk.NewDec(4*common.TO_MICRO), queryResp.Position.Margin) - s.EqualValues(sdk.NewDec(6*common.TO_MICRO), queryResp.Position.OpenNotional) - s.EqualValues(sdk.MustNewDecFromStr("6000000.000000000000000000"), queryResp.PositionNotional) - s.EqualValues(sdk.MustNewDecFromStr("0.000000000000000000"), queryResp.UnrealizedPnl) - s.EqualValues(sdk.MustNewDecFromStr("0.666666666666666667"), queryResp.MarginRatio) + s.EqualValues(sdk.MustNewDecFromStr("996.567342121568550334"), queryResp.Position.Size_) + s.EqualValues(sdk.MustNewDecFromStr("3988000.000000000000000000"), queryResp.Position.Margin) + s.EqualValues(sdk.MustNewDecFromStr("5980000.0"), queryResp.Position.OpenNotional) + s.EqualValues(sdk.MustNewDecFromStr("5979999.999999999999996000"), queryResp.PositionNotional) + s.EqualValues(sdk.MustNewDecFromStr("-0.000000000000004000"), queryResp.UnrealizedPnl) + s.EqualValues(sdk.MustNewDecFromStr("0.666889632107023411"), queryResp.MarginRatio) s.T().Log("D. Open a reverse position smaller than the existing position") txResp, err = s.network.ExecTxCmd(cli.MarketOrderCmd(), user, []string{ @@ -302,8 +302,8 @@ func (s *IntegrationTestSuite) TestMarketOrdersAndCloseCmd() { ammMarketDuo, err = testutilcli.QueryMarketV2(val.ClientCtx, pair) s.Require().NoError(err) s.T().Logf("ammMarketDuo: %s", ammMarketDuo.String()) - s.EqualValues(sdk.MustNewDecFromStr("9999166.736105324556286976"), ammMarketDuo.Amm.BaseReserve) - s.EqualValues(sdk.MustNewDecFromStr("10000833.333333333333333333"), ammMarketDuo.Amm.QuoteReserve) + s.EqualValues(sdk.MustNewDecFromStr("9999169.735606286824650660"), ammMarketDuo.Amm.BaseReserve) + s.EqualValues(sdk.MustNewDecFromStr("10000830.333333333333333334"), ammMarketDuo.Amm.QuoteReserve) s.T().Log("D. Check trader position") queryResp, err = testutilcli.QueryPositionV2(val.ClientCtx, asset.Registry.Pair(denoms.BTC, denoms.NUSD), user) @@ -311,12 +311,14 @@ func (s *IntegrationTestSuite) TestMarketOrdersAndCloseCmd() { s.T().Logf("query response: %+v", queryResp) s.EqualValues(user.String(), queryResp.Position.TraderAddress) s.EqualValues(asset.Registry.Pair(denoms.BTC, denoms.NUSD), queryResp.Position.Pair) - s.EqualValues(sdk.MustNewDecFromStr("833.263894675443713024"), queryResp.Position.Size_) - s.EqualValues(sdk.NewDec(4*common.TO_MICRO), queryResp.Position.Margin) - s.EqualValues(sdk.NewDec(5_000_000), queryResp.Position.OpenNotional) - s.EqualValues(sdk.MustNewDecFromStr("4999999.999999999999998000"), queryResp.PositionNotional) - s.EqualValues(sdk.MustNewDecFromStr("-0.000000000000002000"), queryResp.UnrealizedPnl) - s.EqualValues(sdk.MustNewDecFromStr("0.800000000000000000"), queryResp.MarginRatio) + s.EqualValues(sdk.MustNewDecFromStr("830.264393713175349340"), queryResp.Position.Size_) + s.EqualValues(sdk.MustNewDecFromStr("3987999.999999999999999332"), queryResp.Position.Margin) + s.EqualValues(sdk.MustNewDecFromStr("3987999.999999999999999332"), queryResp.Position.Margin) + + s.EqualValues(sdk.MustNewDecFromStr("4981999.999999999999999332"), queryResp.Position.OpenNotional) + s.EqualValues(sdk.MustNewDecFromStr("4981999.999999999999998000"), queryResp.PositionNotional) + s.EqualValues(sdk.MustNewDecFromStr("-0.000000000000001332"), queryResp.UnrealizedPnl) + s.EqualValues(sdk.MustNewDecFromStr("0.800481734243275793"), queryResp.MarginRatio) s.T().Log("E. Open a reverse position larger than the existing position") txResp, err = s.network.ExecTxCmd(cli.MarketOrderCmd(), user, []string{ @@ -336,11 +338,11 @@ func (s *IntegrationTestSuite) TestMarketOrdersAndCloseCmd() { s.T().Logf("query response: %+v", queryResp) s.EqualValues(user.String(), queryResp.Position.TraderAddress) s.EqualValues(asset.Registry.Pair(denoms.BTC, denoms.NUSD), queryResp.Position.Pair) - s.EqualValues(sdk.MustNewDecFromStr("-500.025001250062503125"), queryResp.Position.Size_) - s.EqualValues(sdk.MustNewDecFromStr("3000000.000000000000002000"), queryResp.Position.OpenNotional) - s.EqualValues(sdk.MustNewDecFromStr("3000000.000000000000002000"), queryResp.Position.Margin) - s.EqualValues(sdk.MustNewDecFromStr("3000000.000000000000000000"), queryResp.PositionNotional) - s.EqualValues(sdk.MustNewDecFromStr("0.000000000000002000"), queryResp.UnrealizedPnl) + s.EqualValues(sdk.MustNewDecFromStr("-500.358367930342114784"), queryResp.Position.Size_) + s.EqualValues(sdk.MustNewDecFromStr("3002000.000000000000002000"), queryResp.Position.OpenNotional) + s.EqualValues(sdk.MustNewDecFromStr("3002000.000000000000002000"), queryResp.Position.Margin) + s.EqualValues(sdk.MustNewDecFromStr("3002000.000000000000004000"), queryResp.PositionNotional) + s.EqualValues(sdk.MustNewDecFromStr("-0.000000000000002000"), queryResp.UnrealizedPnl) // there is a random delta due to twap margin ratio calculation and random block times in the in-process network s.InDelta(1, queryResp.MarginRatio.MustFloat64(), 0.008) @@ -382,8 +384,8 @@ func (s *IntegrationTestSuite) TestPartialCloseCmd() { ammMarketDuo, err := testutilcli.QueryMarketV2(val.ClientCtx, pair) s.Require().NoError(err) s.T().Logf("ammMarketDuo: %s", ammMarketDuo.String()) - s.EqualValues(sdk.MustNewDecFromStr("9998000.399920015996800640"), ammMarketDuo.Amm.BaseReserve) - s.EqualValues(sdk.MustNewDecFromStr("10002000.000000000000000000"), ammMarketDuo.Amm.QuoteReserve) + s.EqualValues(sdk.MustNewDecFromStr("9998004.398322094909855993"), ammMarketDuo.Amm.BaseReserve) + s.EqualValues(sdk.MustNewDecFromStr("10001996.000000000000000001"), ammMarketDuo.Amm.QuoteReserve) s.T().Log("Check trader position") queryResp, err := testutilcli.QueryPositionV2(val.ClientCtx, asset.Registry.Pair(denoms.BTC, denoms.NUSD), user) @@ -391,10 +393,10 @@ func (s *IntegrationTestSuite) TestPartialCloseCmd() { s.T().Logf("query response: %+v", queryResp) s.EqualValues(user.String(), queryResp.Position.TraderAddress) s.EqualValues(pair, queryResp.Position.Pair) - s.EqualValues(sdk.MustNewDecFromStr("1999.600079984003199360"), queryResp.Position.Size_) - s.EqualValues(sdk.NewDec(12e6), queryResp.Position.Margin) - s.EqualValues(sdk.NewDec(12e6), queryResp.Position.OpenNotional) - s.EqualValues(sdk.MustNewDecFromStr("12000000"), queryResp.PositionNotional) + s.EqualValues(sdk.MustNewDecFromStr("1995.601677905090144007"), queryResp.Position.Size_) + s.EqualValues(sdk.MustNewDecFromStr("11976000.000000000000000000"), queryResp.Position.Margin) + s.EqualValues(sdk.MustNewDecFromStr("11976000.000000000000000000"), queryResp.Position.OpenNotional) + s.EqualValues(sdk.MustNewDecFromStr("11976000.000000000000000000"), queryResp.PositionNotional) s.EqualValues(sdk.ZeroDec(), queryResp.UnrealizedPnl) s.EqualValues(sdk.OneDec(), queryResp.MarginRatio) @@ -428,8 +430,8 @@ func (s *IntegrationTestSuite) TestPartialCloseCmd() { ammMarketDuo, err = testutilcli.QueryMarketV2(val.ClientCtx, pair) s.Require().NoError(err) s.T().Logf("ammMarketDuo: %s", ammMarketDuo.String()) - s.EqualValues(sdk.MustNewDecFromStr("9998500.399920015996800640"), ammMarketDuo.Amm.BaseReserve) - s.EqualValues(sdk.MustNewDecFromStr("10001499.824993752062459356"), ammMarketDuo.Amm.QuoteReserve) + s.EqualValues(sdk.MustNewDecFromStr("9998503.398288059264958855"), ammMarketDuo.Amm.BaseReserve) + s.EqualValues(sdk.MustNewDecFromStr("10001496.825727135305804567"), ammMarketDuo.Amm.QuoteReserve) s.T().Log("Check trader position") queryResp, err = testutilcli.QueryPositionV2(val.ClientCtx, asset.Registry.Pair(denoms.BTC, denoms.NUSD), user) @@ -437,12 +439,12 @@ func (s *IntegrationTestSuite) TestPartialCloseCmd() { s.T().Logf("query response: %+v", queryResp) s.EqualValues(user.String(), queryResp.Position.TraderAddress) s.EqualValues(asset.Registry.Pair(denoms.BTC, denoms.NUSD), queryResp.Position.Pair) - s.EqualValues(sdk.MustNewDecFromStr("1499.600079984003199360"), queryResp.Position.Size_) - s.EqualValues(sdk.NewDec(12e6), queryResp.Position.Margin) - s.EqualValues(sdk.MustNewDecFromStr("8998949.962512374756136000"), queryResp.Position.OpenNotional) - s.EqualValues(sdk.MustNewDecFromStr("8998949.962512374756136000"), queryResp.PositionNotional) - s.EqualValues(sdk.ZeroDec(), queryResp.UnrealizedPnl) - s.EqualValues(sdk.MustNewDecFromStr("1.333488912594172945"), queryResp.MarginRatio) + s.EqualValues(sdk.MustNewDecFromStr("1496.601711940735041145"), queryResp.Position.Size_) + s.EqualValues(sdk.MustNewDecFromStr("11976000.000000000000000000"), queryResp.Position.Margin) + s.EqualValues(sdk.MustNewDecFromStr("8980954.362811834827398000"), queryResp.Position.OpenNotional) + s.EqualValues(sdk.MustNewDecFromStr("8980954.362811834827396000"), queryResp.PositionNotional) + s.EqualValues(sdk.MustNewDecFromStr("-0.000000000000002000"), queryResp.UnrealizedPnl) + s.EqualValues(sdk.MustNewDecFromStr("1.333488571057658776"), queryResp.MarginRatio) } func (s *IntegrationTestSuite) TestPositionEmptyAndClose() { @@ -519,7 +521,7 @@ func (s *IntegrationTestSuite) TestX_AddMargin() { fmt.Sprintf("10000%s", denoms.USDT), }, expectFail: false, - expectedMargin: sdk.NewDec(1_000_000), + expectedMargin: sdk.NewDec(980000), expectedCode: 1, }, { @@ -529,7 +531,7 @@ func (s *IntegrationTestSuite) TestX_AddMargin() { fmt.Sprintf("10000%s", types.TestingCollateralDenomNUSD), }, expectedCode: types.ErrPositionNotFound.ABCICode(), - expectedMargin: sdk.NewDec(1_000_000), + expectedMargin: sdk.NewDec(980000), expectFail: false, }, { @@ -539,7 +541,7 @@ func (s *IntegrationTestSuite) TestX_AddMargin() { fmt.Sprintf("10000%s", types.TestingCollateralDenomNUSD), }, expectedCode: 0, - expectedMargin: sdk.NewDec(1_010_000), + expectedMargin: sdk.NewDec(990_000), expectFail: false, }, { @@ -623,7 +625,7 @@ func (s *IntegrationTestSuite) TestX_RemoveMargin() { }, expectFail: false, expectedCode: 1, - expectedMargin: sdk.NewDec(1_000_000), + expectedMargin: sdk.NewDec(980_000), }, { name: "fail: position not found", @@ -632,7 +634,7 @@ func (s *IntegrationTestSuite) TestX_RemoveMargin() { fmt.Sprintf("10000%s", types.TestingCollateralDenomNUSD), }, expectedCode: types.ErrPositionNotFound.ABCICode(), - expectedMargin: sdk.NewDec(1_000_000), + expectedMargin: sdk.NewDec(980_000), expectFail: false, }, { @@ -642,7 +644,7 @@ func (s *IntegrationTestSuite) TestX_RemoveMargin() { fmt.Sprintf("10000%s", types.TestingCollateralDenomNUSD), }, expectedCode: 0, - expectedMargin: sdk.NewDec(990_000), + expectedMargin: sdk.NewDec(970_000), expectFail: false, }, { diff --git a/x/perp/v2/keeper/admin_test.go b/x/perp/v2/keeper/admin_test.go index b2e2840d4..365140995 100644 --- a/x/perp/v2/keeper/admin_test.go +++ b/x/perp/v2/keeper/admin_test.go @@ -280,7 +280,7 @@ func TestCloseMarket(t *testing.T) { ), ).When( CloseMarket(pairBtcUsdc), - AMMShouldBeEqual(pairBtcUsdc, AMM_SettlementPriceShoulBeEqual(sdk.MustNewDecFromStr("1.1"))), + AMMShouldBeEqual(pairBtcUsdc, AMM_SettlementPriceShoulBeEqual(sdk.MustNewDecFromStr("1.099800000000000000"))), ).Then( PartialCloseFails(alice, pairBtcUsdc, sdk.NewDec(5_000), perptypes.ErrMarketNotEnabled), ), diff --git a/x/perp/v2/keeper/clearing_house.go b/x/perp/v2/keeper/clearing_house.go index 35c28abb8..65fe2e61d 100644 --- a/x/perp/v2/keeper/clearing_house.go +++ b/x/perp/v2/keeper/clearing_house.go @@ -64,6 +64,15 @@ func (k Keeper) MarketOrder( sameSideLong := position.Size_.IsPositive() && dir == types.Direction_LONG sameSideShort := position.Size_.IsNegative() && dir == types.Direction_SHORT + openNotionalPreFees := leverage.MulInt(quoteAssetAmt) + transferredFee, err := k.transferFee(ctx, market.Pair, traderAddr, openNotionalPreFees, + market.ExchangeFeeRatio, market.EcosystemFundFeeRatio, + ) + if err != nil { + return nil, err + } + quoteAssetAmtMinusFees := quoteAssetAmt.Sub(transferredFee) + var updatedAMM *types.AMM openSideMatchesPosition := sameSideLong || sameSideShort if isNewPosition || openSideMatchesPosition { @@ -73,14 +82,14 @@ func (k Keeper) MarketOrder( amm, position, dir, - /* openNotional */ leverage.MulInt(quoteAssetAmt), + /* openNotional */ leverage.MulInt(quoteAssetAmtMinusFees), /* minPositionSize */ baseAmtLimit, /* leverage */ leverage) if err != nil { return nil, err } } else { - quoteAssetAmtToDec := sdk.NewDecFromInt(quoteAssetAmt) + quoteAssetAmtToDec := sdk.NewDecFromInt(quoteAssetAmtMinusFees) updatedAMM, positionResp, err = k.openReversePosition( ctx, market, @@ -108,7 +117,7 @@ func (k Keeper) MarketOrder( } if err = k.afterPositionUpdate( - ctx, market, *updatedAMM, traderAddr, *positionResp, types.ChangeReason_MarketOrder, position, + ctx, market, traderAddr, *positionResp, types.ChangeReason_MarketOrder, transferredFee, position, ); err != nil { return nil, err } @@ -531,10 +540,10 @@ func checkMarketOrderRequirements(market types.Market, quoteAssetAmt sdkmath.Int func (k Keeper) afterPositionUpdate( ctx sdk.Context, market types.Market, - amm types.AMM, traderAddr sdk.AccAddress, positionResp types.PositionResp, changeType types.ChangeReason, + transferredFee sdkmath.Int, existingPosition types.Position, ) (err error) { // transfer trader <=> vault @@ -558,13 +567,6 @@ func (k Keeper) afterPositionUpdate( } } - transferredFee, err := k.transferFee(ctx, market.Pair, traderAddr, positionResp.ExchangedNotionalValue, - market.ExchangeFeeRatio, market.EcosystemFundFeeRatio, - ) - if err != nil { - return err - } - if !positionResp.Position.Size_.IsZero() { k.SavePosition(ctx, market.Pair, market.Version, traderAddr, positionResp.Position) } @@ -579,6 +581,17 @@ func (k Keeper) afterPositionUpdate( positionNotional = positionResp.Position.OpenNotional.Sub(positionResp.UnrealizedPnlAfter) } + // This means that the position has been closed entirely. + if transferredFee.IsZero() { + // If the position has margin to be transferred to the user, we get the fees from it. + if positionResp.MarginToVault.IsNegative() { + transferredFee, err = k.transferFee(ctx, market.Pair, traderAddr, positionResp.MarginToVault.Abs(), market.ExchangeFeeRatio, market.EcosystemFundFeeRatio) + if err != nil { + return err + } + } + } + _ = ctx.EventManager().EmitTypedEvents( &types.PositionChangedEvent{ FinalPosition: positionResp.Position, @@ -718,7 +731,7 @@ func (k Keeper) ClosePosition(ctx sdk.Context, pair asset.Pair, traderAddr sdk.A return nil, err } - updatedAMM, positionResp, err := k.closePositionEntirely( + _, positionResp, err := k.closePositionEntirely( ctx, market, amm, @@ -742,10 +755,10 @@ func (k Keeper) ClosePosition(ctx sdk.Context, pair asset.Pair, traderAddr sdk.A if err = k.afterPositionUpdate( ctx, market, - *updatedAMM, traderAddr, *positionResp, types.ChangeReason_ClosePosition, + sdk.ZeroInt(), position, ); err != nil { return nil, err @@ -889,7 +902,14 @@ func (k Keeper) PartialClose( } reverseNotionalAmt = amm.QuoteReserveToAsset(reverseNotionalAmt) - updatedAMM, positionResp, err := k.decreasePosition(ctx, market, amm, position, reverseNotionalAmt, sdk.ZeroDec()) + feesTransferred, err := k.transferFee(ctx, market.Pair, traderAddr, reverseNotionalAmt, market.ExchangeFeeRatio, market.EcosystemFundFeeRatio) + if err != nil { + return nil, err + } + + reverseNotionalAmtWithoutFees := reverseNotionalAmt.Sub(feesTransferred.ToLegacyDec()) + + _, positionResp, err := k.decreasePosition(ctx, market, amm, position, reverseNotionalAmtWithoutFees, sdk.ZeroDec()) if err != nil { return nil, err } @@ -907,10 +927,10 @@ func (k Keeper) PartialClose( err = k.afterPositionUpdate( ctx, market, - *updatedAMM, traderAddr, *positionResp, types.ChangeReason_PartialClose, + feesTransferred, position, ) if err != nil { diff --git a/x/perp/v2/keeper/clearing_house_test.go b/x/perp/v2/keeper/clearing_house_test.go index b8e62e28c..3fcbb8305 100644 --- a/x/perp/v2/keeper/clearing_house_test.go +++ b/x/perp/v2/keeper/clearing_house_test.go @@ -73,29 +73,29 @@ func TestMarketOrder(t *testing.T) { types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(1000), - OpenNotional: sdk.NewDec(10_000), - Size_: sdk.MustNewDecFromStr("9999.999900000001"), + Margin: sdk.NewDec(980), + OpenNotional: sdk.NewDec(9_800), + Size_: sdk.MustNewDecFromStr("9799.999903960000941192"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.ZeroDec(), }), - MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(10_000)), // margin * leverage - MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("9999.999900000001")), + MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(9_800)), // margin * leverage + MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("9799.999903960000941192")), MarketOrderResp_BadDebtShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_FundingPaymentShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_RealizedPnlShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_UnrealizedPnlAfterShouldBeEqual(sdk.ZeroDec()), - MarketOrderResp_MarginToVaultShouldBeEqual(sdk.NewDec(1000)), - MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(10_000)), + MarketOrderResp_MarginToVaultShouldBeEqual(sdk.NewDec(980)), + MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(9800)), ), ). Then( PositionShouldBeEqual(alice, pairBtcNusd, Position_PositionShouldBeEqualTo(types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(1000), - OpenNotional: sdk.NewDec(10_000), - Size_: sdk.MustNewDecFromStr("9999.999900000001"), + Margin: sdk.NewDec(980), + OpenNotional: sdk.NewDec(9800), + Size_: sdk.MustNewDecFromStr("9799.999903960000941192"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.ZeroDec(), })), @@ -103,23 +103,23 @@ func TestMarketOrder(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(1000), - OpenNotional: sdk.NewDec(10_000), - Size_: sdk.MustNewDecFromStr("9999.999900000001"), + Margin: sdk.NewDec(980), + OpenNotional: sdk.NewDec(9800), + Size_: sdk.MustNewDecFromStr("9799.999903960000941192"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, - PositionNotional: sdk.NewDec(10_000), + PositionNotional: sdk.NewDec(9800), RealizedPnl: sdk.ZeroDec(), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.ZeroDec(), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(20)), BlockHeight: 1, // exchangedMargin = - marginToVault - transferredFee - MarginToUser: sdk.NewInt(1_000 + 20).Neg(), + MarginToUser: sdk.NewInt(980 + 20).Neg(), ChangeReason: types.ChangeReason_MarketOrder, - ExchangedNotional: sdk.MustNewDecFromStr("10000.000000000000000000"), - ExchangedSize: sdk.MustNewDecFromStr("9999.999900000001000000"), + ExchangedNotional: sdk.NewDec(9800), + ExchangedSize: sdk.MustNewDecFromStr("9799.999903960000941192"), }), ), @@ -138,20 +138,20 @@ func TestMarketOrder(t *testing.T) { types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(2000), - OpenNotional: sdk.NewDec(20_000), - Size_: sdk.MustNewDecFromStr("19999.999600000008000000"), + Margin: sdk.NewDec(1_960), + OpenNotional: sdk.NewDec(19_600), + Size_: sdk.MustNewDecFromStr("19599.999615840007529536"), LastUpdatedBlockNumber: 2, LatestCumulativePremiumFraction: sdk.ZeroDec(), }), - MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(10_000)), // margin * leverage - MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("9999.999700000007000000")), + MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(9_800)), // margin * leverage + MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("9799.999711880006588344")), MarketOrderResp_BadDebtShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_FundingPaymentShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_RealizedPnlShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_UnrealizedPnlAfterShouldBeEqual(sdk.ZeroDec()), - MarketOrderResp_MarginToVaultShouldBeEqual(sdk.NewDec(1000)), - MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(20_000)), + MarketOrderResp_MarginToVaultShouldBeEqual(sdk.NewDec(980)), + MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(19_600)), ), ). Then( @@ -159,23 +159,23 @@ func TestMarketOrder(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(2000), - OpenNotional: sdk.NewDec(20_000), - Size_: sdk.MustNewDecFromStr("19999.999600000008000000"), + Margin: sdk.NewDec(1_960), + OpenNotional: sdk.NewDec(19_600), + Size_: sdk.MustNewDecFromStr("19599.999615840007529536"), LastUpdatedBlockNumber: 2, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, - PositionNotional: sdk.NewDec(20_000), + PositionNotional: sdk.NewDec(19_600), RealizedPnl: sdk.ZeroDec(), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.ZeroDec(), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(20)), // 20 bps BlockHeight: 2, // exchangedMargin = - marginToVault - transferredFee - MarginToUser: sdk.NewInt(1_000 + 20).Neg(), + MarginToUser: sdk.NewInt(980 + 20).Neg(), ChangeReason: types.ChangeReason_MarketOrder, - ExchangedNotional: sdk.MustNewDecFromStr("10000.000000000000000000"), - ExchangedSize: sdk.MustNewDecFromStr("9999.999700000007000000"), + ExchangedNotional: sdk.MustNewDecFromStr("9800.000000000000000000"), + ExchangedSize: sdk.MustNewDecFromStr("9799.999711880006588344"), }), ), @@ -288,21 +288,21 @@ func TestMarketOrder(t *testing.T) { types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(1000), - OpenNotional: sdk.NewDec(5000), - Size_: sdk.MustNewDecFromStr("4999.999975000000125000"), + Margin: sdk.NewDec(980), + OpenNotional: sdk.NewDec(4_900), + Size_: sdk.MustNewDecFromStr("4899.999975990000117649"), LastUpdatedBlockNumber: 2, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, ), - MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(5000)), // margin * leverage - MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("-4999.999925000000875000")), + MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(4_900)), // (margin - fees) * leverage + MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("-4899.999927970000823543")), MarketOrderResp_BadDebtShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_FundingPaymentShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_RealizedPnlShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_UnrealizedPnlAfterShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_MarginToVaultShouldBeEqual(sdk.ZeroDec()), - MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(5000)), + MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(4_900)), ), ). Then( @@ -310,13 +310,13 @@ func TestMarketOrder(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(1000), - OpenNotional: sdk.NewDec(5000), - Size_: sdk.MustNewDecFromStr("4999.999975000000125000"), + Margin: sdk.NewDec(980), + OpenNotional: sdk.NewDec(4_900), + Size_: sdk.MustNewDecFromStr("4899.999975990000117649"), LastUpdatedBlockNumber: 2, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, - PositionNotional: sdk.NewDec(5000), + PositionNotional: sdk.NewDec(4_900), RealizedPnl: sdk.ZeroDec(), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.ZeroDec(), @@ -325,8 +325,8 @@ func TestMarketOrder(t *testing.T) { // exchangedMargin = - marginToVault - transferredFee MarginToUser: sdk.NewInt(0 + 10).Neg(), ChangeReason: types.ChangeReason_MarketOrder, - ExchangedNotional: sdk.MustNewDecFromStr("-5000.000000000000000000"), - ExchangedSize: sdk.MustNewDecFromStr("-4999.999925000000875000"), + ExchangedNotional: sdk.MustNewDecFromStr("-4900.000000000000000000"), + ExchangedSize: sdk.MustNewDecFromStr("-4899.999927970000823543"), }), ), @@ -382,21 +382,21 @@ func TestMarketOrder(t *testing.T) { types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(2000), - OpenNotional: sdk.NewDec(20000), - Size_: sdk.MustNewDecFromStr("-20000.000400000008000000"), + Margin: sdk.NewDec(1960), + OpenNotional: sdk.NewDec(19_600), + Size_: sdk.MustNewDecFromStr("-19600.000384160007529536"), LastUpdatedBlockNumber: 2, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, ), - MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(30000)), // margin * leverage - MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("-30000.000300000009000000")), + MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(29_400)), // margin * leverage + MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("-29400.000288120008470728")), MarketOrderResp_BadDebtShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_FundingPaymentShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_RealizedPnlShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_UnrealizedPnlAfterShouldBeEqual(sdk.ZeroDec()), - MarketOrderResp_MarginToVaultShouldBeEqual(sdk.NewDec(1000)), - MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(20000)), + MarketOrderResp_MarginToVaultShouldBeEqual(sdk.NewDec(980)), + MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(19_600)), ), ). Then( @@ -404,23 +404,23 @@ func TestMarketOrder(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(2000), - OpenNotional: sdk.NewDec(20000), - Size_: sdk.MustNewDecFromStr("-20000.000400000008000000"), + Margin: sdk.NewDec(1960), + OpenNotional: sdk.NewDec(19_600), + Size_: sdk.MustNewDecFromStr("-19600.000384160007529536"), LastUpdatedBlockNumber: 2, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, - PositionNotional: sdk.NewDec(20000), + PositionNotional: sdk.NewDec(19_600), RealizedPnl: sdk.ZeroDec(), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.ZeroDec(), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(60)), // 20 bps BlockHeight: 2, // exchangedMargin = - marginToVault - transferredFee - MarginToUser: sdk.NewInt(1_000 + 60).Neg(), + MarginToUser: sdk.NewInt(980 + 60).Neg(), ChangeReason: types.ChangeReason_MarketOrder, - ExchangedNotional: sdk.MustNewDecFromStr("10000.000000000000000000"), - ExchangedSize: sdk.MustNewDecFromStr("-30000.000300000009000000"), + ExchangedNotional: sdk.MustNewDecFromStr("9800.000000000000000000"), + ExchangedSize: sdk.MustNewDecFromStr("-29400.000288120008470728"), }), ), @@ -433,7 +433,7 @@ func TestMarketOrder(t *testing.T) { ), SetBlockNumber(1), SetBlockTime(startBlockTime), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(18)))), + FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(150)))), InsertPosition( WithPair(pairBtcNusd), WithTrader(alice), @@ -481,9 +481,9 @@ func TestMarketOrder(t *testing.T) { RealizedPnl: sdk.MustNewDecFromStr("-1100.000088999999110000"), BadDebt: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 102), FundingPayment: sdk.NewDec(2), - TransactionFee: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 18), // 20 bps + TransactionFee: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 60), // 20 bps BlockHeight: 2, - MarginToUser: sdk.NewInt(-18), + MarginToUser: sdk.NewInt(-60), ChangeReason: types.ChangeReason_MarketOrder, ExchangedNotional: sdk.MustNewDecFromStr("-10000.000000000000000000"), ExchangedSize: sdk.MustNewDecFromStr("-10000.000000000000000000"), @@ -503,20 +503,20 @@ func TestMarketOrder(t *testing.T) { types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(1000), - OpenNotional: sdk.NewDec(10_000), - Size_: sdk.MustNewDecFromStr("-10000.000100000001000000"), + Margin: sdk.NewDec(980), + OpenNotional: sdk.NewDec(9_800), + Size_: sdk.MustNewDecFromStr("-9800.000096040000941192"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.ZeroDec(), }), - MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(10_000)), // margin * leverage - MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("-10000.000100000001000000")), + MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(9_800)), // margin * leverage + MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("-9800.000096040000941192")), MarketOrderResp_BadDebtShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_FundingPaymentShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_RealizedPnlShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_UnrealizedPnlAfterShouldBeEqual(sdk.ZeroDec()), - MarketOrderResp_MarginToVaultShouldBeEqual(sdk.NewDec(1000)), - MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(10_000)), + MarketOrderResp_MarginToVaultShouldBeEqual(sdk.NewDec(980)), + MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(9_800)), ), ). Then( @@ -524,9 +524,9 @@ func TestMarketOrder(t *testing.T) { Position_PositionShouldBeEqualTo(types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(1000), - OpenNotional: sdk.NewDec(10_000), - Size_: sdk.MustNewDecFromStr("-10000.000100000001000000"), + Margin: sdk.NewDec(980), + OpenNotional: sdk.NewDec(9_800), + Size_: sdk.MustNewDecFromStr("-9800.000096040000941192"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.ZeroDec(), }), @@ -535,23 +535,23 @@ func TestMarketOrder(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(1000), - OpenNotional: sdk.NewDec(10_000), - Size_: sdk.MustNewDecFromStr("-10000.000100000001000000"), + Margin: sdk.NewDec(980), + OpenNotional: sdk.NewDec(9_800), + Size_: sdk.MustNewDecFromStr("-9800.000096040000941192"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, - PositionNotional: sdk.NewDec(10_000), + PositionNotional: sdk.NewDec(9_800), RealizedPnl: sdk.ZeroDec(), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.ZeroDec(), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(20)), BlockHeight: 1, // exchangedMargin = - marginToVault - transferredFee - MarginToUser: sdk.NewInt(1_000 + 20).Neg(), + MarginToUser: sdk.NewInt(980 + 20).Neg(), ChangeReason: types.ChangeReason_MarketOrder, - ExchangedNotional: sdk.MustNewDecFromStr("10000.000000000000000000"), - ExchangedSize: sdk.MustNewDecFromStr("-10000.000100000001000000"), + ExchangedNotional: sdk.MustNewDecFromStr("9800.000000000000000000"), + ExchangedSize: sdk.MustNewDecFromStr("-9800.000096040000941192"), }), ), @@ -570,21 +570,21 @@ func TestMarketOrder(t *testing.T) { types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(2000), - OpenNotional: sdk.NewDec(20_000), - Size_: sdk.MustNewDecFromStr("-20000.000400000008000000"), + Margin: sdk.NewDec(1_960), + OpenNotional: sdk.NewDec(19_600), + Size_: sdk.MustNewDecFromStr("-19600.000384160007529536"), LastUpdatedBlockNumber: 2, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, ), - MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(10_000)), // margin * leverage - MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("-10000.000300000007000000")), + MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(9_800)), // margin * leverage + MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("-9800.000288120006588344")), MarketOrderResp_BadDebtShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_FundingPaymentShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_RealizedPnlShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_UnrealizedPnlAfterShouldBeEqual(sdk.ZeroDec()), - MarketOrderResp_MarginToVaultShouldBeEqual(sdk.NewDec(1000)), - MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(20_000)), + MarketOrderResp_MarginToVaultShouldBeEqual(sdk.NewDec(980)), + MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(19_600)), ), ). Then( @@ -592,23 +592,23 @@ func TestMarketOrder(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(2000), - OpenNotional: sdk.NewDec(20_000), - Size_: sdk.MustNewDecFromStr("-20000.000400000008000000"), + Margin: sdk.NewDec(1_960), + OpenNotional: sdk.NewDec(19_600), + Size_: sdk.MustNewDecFromStr("-19600.000384160007529536"), LastUpdatedBlockNumber: 2, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, - PositionNotional: sdk.NewDec(20_000), + PositionNotional: sdk.NewDec(19_600), RealizedPnl: sdk.ZeroDec(), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.ZeroDec(), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(20)), // 20 bps BlockHeight: 2, // exchangedMargin = - marginToVault - transferredFee - MarginToUser: sdk.NewInt(1_000 + 20).Neg(), + MarginToUser: sdk.NewInt(980 + 20).Neg(), ChangeReason: types.ChangeReason_MarketOrder, - ExchangedNotional: sdk.MustNewDecFromStr("10000.000000000000000000"), - ExchangedSize: sdk.MustNewDecFromStr("-10000.000300000007000000"), + ExchangedNotional: sdk.MustNewDecFromStr("9800.000000000000000000"), + ExchangedSize: sdk.MustNewDecFromStr("-9800.000288120006588344"), }), ), @@ -662,21 +662,21 @@ func TestMarketOrder(t *testing.T) { types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(1000), - OpenNotional: sdk.NewDec(5000), - Size_: sdk.MustNewDecFromStr("-5000.000025000000125000"), + Margin: sdk.NewDec(980), + OpenNotional: sdk.NewDec(4_900), + Size_: sdk.MustNewDecFromStr("-4900.000024010000117649"), LastUpdatedBlockNumber: 2, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, ), - MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(5000)), // margin * leverage - MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("5000.000075000000875000")), + MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(4_900)), // margin * leverage + MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("4900.000072030000823543")), MarketOrderResp_BadDebtShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_FundingPaymentShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_RealizedPnlShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_UnrealizedPnlAfterShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_MarginToVaultShouldBeEqual(sdk.ZeroDec()), - MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(5000)), + MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(4900)), ), ). Then( @@ -684,13 +684,13 @@ func TestMarketOrder(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(1000), - OpenNotional: sdk.NewDec(5000), - Size_: sdk.MustNewDecFromStr("-5000.000025000000125000"), + Margin: sdk.NewDec(980), + OpenNotional: sdk.NewDec(4_900), + Size_: sdk.MustNewDecFromStr("-4900.000024010000117649"), LastUpdatedBlockNumber: 2, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, - PositionNotional: sdk.NewDec(5000), + PositionNotional: sdk.NewDec(4_900), RealizedPnl: sdk.ZeroDec(), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.ZeroDec(), @@ -699,8 +699,8 @@ func TestMarketOrder(t *testing.T) { // exchangedMargin = - marginToVault - transferredFee MarginToUser: sdk.NewInt(0 + 10).Neg(), ChangeReason: types.ChangeReason_MarketOrder, - ExchangedNotional: sdk.MustNewDecFromStr("-5000.000000000000000000"), - ExchangedSize: sdk.MustNewDecFromStr("5000.000075000000875000"), + ExchangedNotional: sdk.MustNewDecFromStr("-4900.000000000000000000"), + ExchangedSize: sdk.MustNewDecFromStr("4900.000072030000823543"), }), ), @@ -755,21 +755,21 @@ func TestMarketOrder(t *testing.T) { types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(2000), - OpenNotional: sdk.NewDec(20000), - Size_: sdk.MustNewDecFromStr("19999.999600000008000000"), + Margin: sdk.NewDec(1960), + OpenNotional: sdk.NewDec(19_600), + Size_: sdk.MustNewDecFromStr("19599.999615840007529536"), LastUpdatedBlockNumber: 2, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, ), - MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(30000)), // margin * leverage - MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("29999.999700000009000000")), + MarketOrderResp_ExchangeNotionalValueShouldBeEqual(sdk.NewDec(29_400)), // margin * leverage + MarketOrderResp_ExchangedPositionSizeShouldBeEqual(sdk.MustNewDecFromStr("29399.999711880008470728")), MarketOrderResp_BadDebtShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_FundingPaymentShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_RealizedPnlShouldBeEqual(sdk.ZeroDec()), MarketOrderResp_UnrealizedPnlAfterShouldBeEqual(sdk.ZeroDec()), - MarketOrderResp_MarginToVaultShouldBeEqual(sdk.NewDec(1000)), - MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(20000)), + MarketOrderResp_MarginToVaultShouldBeEqual(sdk.NewDec(980)), + MarketOrderResp_PositionNotionalShouldBeEqual(sdk.NewDec(19_600)), ), ). Then( @@ -777,23 +777,23 @@ func TestMarketOrder(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.NewDec(2000), - OpenNotional: sdk.NewDec(20000), - Size_: sdk.MustNewDecFromStr("19999.999600000008000000"), + Margin: sdk.NewDec(1960), + OpenNotional: sdk.NewDec(19_600), + Size_: sdk.MustNewDecFromStr("19599.999615840007529536"), LastUpdatedBlockNumber: 2, LatestCumulativePremiumFraction: sdk.ZeroDec(), }, - PositionNotional: sdk.NewDec(20000), + PositionNotional: sdk.NewDec(19_600), RealizedPnl: sdk.ZeroDec(), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.ZeroDec(), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(60)), // 20 bps BlockHeight: 2, // exchangedMargin = - marginToVault - transferredFee - MarginToUser: sdk.NewInt(1_000 + 60).Neg(), + MarginToUser: sdk.NewInt(980 + 60).Neg(), ChangeReason: types.ChangeReason_MarketOrder, - ExchangedNotional: sdk.MustNewDecFromStr("10000.000000000000000000"), - ExchangedSize: sdk.MustNewDecFromStr("29999.999700000009000000"), + ExchangedNotional: sdk.MustNewDecFromStr("9800.000000000000000000"), + ExchangedSize: sdk.MustNewDecFromStr("29399.999711880008470728"), }), ), @@ -805,7 +805,7 @@ func TestMarketOrder(t *testing.T) { ), SetBlockNumber(1), SetBlockTime(startBlockTime), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(22)))), + FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(150)))), InsertPosition( WithPair(pairBtcNusd), WithTrader(alice), @@ -853,10 +853,10 @@ func TestMarketOrder(t *testing.T) { RealizedPnl: sdk.MustNewDecFromStr("-1100.000111000001110000"), BadDebt: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 98), FundingPayment: sdk.NewDec(-2), - TransactionFee: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 22), // 20 bps + TransactionFee: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 60), // 20 bps BlockHeight: 2, // exchangedMargin = - marginToVault - transferredFee - MarginToUser: sdk.NewInt(-22), + MarginToUser: sdk.NewInt(-60), ChangeReason: types.ChangeReason_MarketOrder, ExchangedNotional: sdk.MustNewDecFromStr("-10000.000000000000000000"), ExchangedSize: sdk.MustNewDecFromStr("10000.000000000000000000"), @@ -953,95 +953,6 @@ func TestMarketOrder(t *testing.T) { Then( PositionShouldNotExist(alice, pairBtcNusd, 1), ), - - TC("position should not exist after opening a closing manually"). - Given( - SetBlockTime(startBlockTime), - SetBlockNumber(1), - CreateCustomMarket(pairBtcNusd, - WithEnabled(true), - WithPricePeg(sdk.MustNewDecFromStr("25001.0112"))), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(20_000_000_000+20_000_000)))), - ). - When( - MarketOrder(alice, pairBtcNusd, types.Direction_SHORT, sdk.NewInt(10_000_000_000), sdk.OneDec(), sdk.ZeroDec()), - MarketOrder(alice, pairBtcNusd, types.Direction_LONG, sdk.NewInt(10_000_000_000), sdk.OneDec(), sdk.ZeroDec()), - ). - Then( - PositionShouldNotExist(alice, pairBtcNusd, 1), - ), - - TC("position should not exist after opening a closing manually - reverse with leverage"). - Given( - SetBlockTime(startBlockTime), - SetBlockNumber(1), - CreateCustomMarket( - pairBtcNusd, - WithEnabled(true), - WithPricePeg(sdk.MustNewDecFromStr("25001.0112"))), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1e6)))), - ). - When( - MarketOrder(alice, pairBtcNusd, types.Direction_SHORT, sdk.NewInt(100_000), sdk.OneDec(), sdk.ZeroDec()), - MarketOrder(alice, pairBtcNusd, types.Direction_LONG, sdk.NewInt(50_000), sdk.NewDec(2), sdk.ZeroDec()), - ). - Then( - PositionShouldNotExist(alice, pairBtcNusd, 1), - ), - TC("position should not exist after opening a closing manually - open with leverage"). - Given( - SetBlockTime(startBlockTime), - SetBlockNumber(1), - CreateCustomMarket( - pairBtcNusd, - WithEnabled(true), - WithPricePeg(sdk.MustNewDecFromStr("25001.0112"))), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1e6)))), - ). - When( - MarketOrder(alice, pairBtcNusd, types.Direction_LONG, sdk.NewInt(50_000), sdk.NewDec(2), sdk.ZeroDec()), - MarketOrder(alice, pairBtcNusd, types.Direction_SHORT, sdk.NewInt(100_000), sdk.OneDec(), sdk.ZeroDec()), - ). - Then( - PositionShouldNotExist(alice, pairBtcNusd, 1), - ), - - TC("position should not exist after opening a closing manually - reverse with leverage"). - Given( - SetBlockTime(startBlockTime), - SetBlockNumber(1), - CreateCustomMarket( - pairBtcNusd, - WithEnabled(true), - WithPricePeg(sdk.MustNewDecFromStr("25001.0112"))), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1e6)))), - ). - When( - MarketOrder(alice, pairBtcNusd, types.Direction_SHORT, sdk.NewInt(100_000), sdk.OneDec(), sdk.ZeroDec()), - MarketOrder(alice, pairBtcNusd, types.Direction_LONG, sdk.NewInt(50_000), sdk.NewDec(2), sdk.ZeroDec()), - ). - Then( - PositionShouldNotExist(alice, pairBtcNusd, 1), - ), - - TC("position should not exist after opening a closing manually - reverse with leverage - more steps"). - Given( - SetBlockTime(startBlockTime), - SetBlockNumber(1), - CreateCustomMarket( - pairBtcNusd, - WithEnabled(true), - WithPricePeg(sdk.MustNewDecFromStr("25000"))), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1e6)))), - ). - When( - MarketOrder(alice, pairBtcNusd, types.Direction_SHORT, sdk.NewInt(100_000), sdk.OneDec(), sdk.ZeroDec()), - MarketOrder(alice, pairBtcNusd, types.Direction_LONG, sdk.NewInt(50_000), sdk.NewDec(4), sdk.ZeroDec()), - MarketOrder(alice, pairBtcNusd, types.Direction_SHORT, sdk.NewInt(50_000), sdk.NewDec(2), sdk.ZeroDec()), - ). - Then( - PositionShouldNotExist(alice, pairBtcNusd, 1), - ), } NewTestSuite(t).WithTestCases(tc...).Run() @@ -1106,7 +1017,7 @@ func TestMarketOrderError(t *testing.T) { side: types.Direction_SHORT, margin: sdk.NewInt(1000), leverage: sdk.NewDec(10), - baseLimit: sdk.NewDec(10_000), + baseLimit: sdk.NewDec(9_800), expectedErr: types.ErrAssetFailsUserLimit, }, { @@ -1197,7 +1108,7 @@ func TestPartialClose(t *testing.T) { ), SetBlockTime(startBlockTime), SetBlockNumber(1), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(10)))), + FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1000)))), InsertPosition( WithPair(pairBtcNusd), WithTrader(alice), @@ -1213,9 +1124,9 @@ func TestPartialClose(t *testing.T) { PositionShouldBeEqual(alice, pairBtcNusd, Position_PositionShouldBeEqualTo(types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.MustNewDecFromStr("3497.999950000000500000"), - OpenNotional: sdk.MustNewDecFromStr("7499.999962500000468750"), - Size_: sdk.MustNewDecFromStr("7500.000000000000000000"), + Margin: sdk.MustNewDecFromStr("3492.999950075025499499"), + OpenNotional: sdk.MustNewDecFromStr("7504.999962575025468249"), + Size_: sdk.MustNewDecFromStr("7505.000000024975000031"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), })), @@ -1223,22 +1134,22 @@ func TestPartialClose(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.MustNewDecFromStr("3497.999950000000500000"), - OpenNotional: sdk.MustNewDecFromStr("7499.999962500000468750"), - Size_: sdk.MustNewDecFromStr("7500.000000000000000000"), + Margin: sdk.MustNewDecFromStr("3492.999950075025499499"), + OpenNotional: sdk.MustNewDecFromStr("7504.999962575025468249"), + Size_: sdk.MustNewDecFromStr("7505.000000024975000031"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), }, - PositionNotional: sdk.MustNewDecFromStr("14999.999812500001968750"), - RealizedPnl: sdk.MustNewDecFromStr("2499.999950000000500000"), + PositionNotional: sdk.MustNewDecFromStr("15009.999812500001968750"), + RealizedPnl: sdk.MustNewDecFromStr("2494.999950075025499499"), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.NewDec(2), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(10)), BlockHeight: 1, MarginToUser: sdk.NewInt(-10), ChangeReason: types.ChangeReason_PartialClose, - ExchangedNotional: sdk.MustNewDecFromStr("4999.999812500001968750"), - ExchangedSize: sdk.MustNewDecFromStr("-2500.000000000000000000"), + ExchangedNotional: sdk.MustNewDecFromStr("5009.999812500001968750"), + ExchangedSize: sdk.MustNewDecFromStr("-2494.999999975024999969"), }), ), @@ -1268,9 +1179,9 @@ func TestPartialClose(t *testing.T) { PositionShouldBeEqual(alice, pairBtcNusd, Position_PositionShouldBeEqualTo(types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.MustNewDecFromStr("872.999976250000237500"), - OpenNotional: sdk.MustNewDecFromStr("7499.999982187500222656"), - Size_: sdk.MustNewDecFromStr("7500.000000000000000000"), + Margin: sdk.MustNewDecFromStr("873.210502606841456300"), + OpenNotional: sdk.MustNewDecFromStr("7504.210508544341441456"), + Size_: sdk.MustNewDecFromStr("7504.210526336824376757"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), })), @@ -1278,22 +1189,22 @@ func TestPartialClose(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.MustNewDecFromStr("872.999976250000237500"), - OpenNotional: sdk.MustNewDecFromStr("7499.999982187500222656"), - Size_: sdk.MustNewDecFromStr("7500.000000000000000000"), + Margin: sdk.MustNewDecFromStr("873.210502606841456300"), + OpenNotional: sdk.MustNewDecFromStr("7504.210508544341441456"), + Size_: sdk.MustNewDecFromStr("7504.210526336824376757"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), }, - PositionNotional: sdk.MustNewDecFromStr("7124.999910937500935156"), - RealizedPnl: sdk.MustNewDecFromStr("-125.000023749999762500"), + PositionNotional: sdk.MustNewDecFromStr("7128.999910937500935156"), + RealizedPnl: sdk.MustNewDecFromStr("-124.789497393158543700"), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.NewDec(2), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(4)), BlockHeight: 1, MarginToUser: sdk.NewInt(-4), ChangeReason: types.ChangeReason_PartialClose, - ExchangedNotional: sdk.MustNewDecFromStr("-2875.000089062499064844"), - ExchangedSize: sdk.MustNewDecFromStr("-2500.000000000000000000"), + ExchangedNotional: sdk.MustNewDecFromStr("-2871.000089062499064844"), + ExchangedSize: sdk.MustNewDecFromStr("-2495.789473663175623243"), }), ), @@ -1323,9 +1234,9 @@ func TestPartialClose(t *testing.T) { PositionShouldBeEqual(alice, pairBtcNusd, Position_PositionShouldBeEqualTo(types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.MustNewDecFromStr("847.999976500000235000"), - OpenNotional: sdk.MustNewDecFromStr("7499.999982375000220312"), - Size_: sdk.MustNewDecFromStr("7499.999999999999999999"), + Margin: sdk.MustNewDecFromStr("848.255295690211914400"), + OpenNotional: sdk.MustNewDecFromStr("7504.255301565211899712"), + Size_: sdk.MustNewDecFromStr("7504.255319170194658242"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), })), @@ -1333,22 +1244,22 @@ func TestPartialClose(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.MustNewDecFromStr("847.999976500000235000"), - OpenNotional: sdk.MustNewDecFromStr("7499.999982375000220312"), - Size_: sdk.MustNewDecFromStr("7499.999999999999999999"), + Margin: sdk.MustNewDecFromStr("848.255295690211914400"), + OpenNotional: sdk.MustNewDecFromStr("7504.255301565211899712"), + Size_: sdk.MustNewDecFromStr("7504.255319170194658242"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), }, - PositionNotional: sdk.MustNewDecFromStr("7049.999911875000925312"), - RealizedPnl: sdk.MustNewDecFromStr("-150.000023499999765000"), + PositionNotional: sdk.MustNewDecFromStr("7053.999911875000925312"), + RealizedPnl: sdk.MustNewDecFromStr("-149.744704309788085600"), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.NewDec(2), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(4)), BlockHeight: 1, MarginToUser: sdk.NewInt(-4), ChangeReason: types.ChangeReason_PartialClose, - ExchangedNotional: sdk.MustNewDecFromStr("-2950.000088124999074688"), - ExchangedSize: sdk.MustNewDecFromStr("-2500.000000000000000001"), + ExchangedNotional: sdk.MustNewDecFromStr("-2946.000088124999074688"), + ExchangedSize: sdk.MustNewDecFromStr("-2495.744680829805341758"), })), TC("partial close long position with bad debt"). @@ -1379,8 +1290,8 @@ func TestPartialClose(t *testing.T) { Pair: pairBtcNusd, TraderAddress: alice.String(), Margin: sdk.ZeroDec(), - OpenNotional: sdk.MustNewDecFromStr("7499.999988937500138281"), - Size_: sdk.MustNewDecFromStr("7500.000000000000000000"), + OpenNotional: sdk.MustNewDecFromStr("7503.389819472919156581"), + Size_: sdk.MustNewDecFromStr("7503.389830525412237884"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), })), @@ -1389,21 +1300,21 @@ func TestPartialClose(t *testing.T) { Pair: pairBtcNusd, TraderAddress: alice.String(), Margin: sdk.ZeroDec(), - OpenNotional: sdk.MustNewDecFromStr("7499.999988937500138281"), - Size_: sdk.MustNewDecFromStr("7500.000000000000000000"), + OpenNotional: sdk.MustNewDecFromStr("7503.389819472919156581"), + Size_: sdk.MustNewDecFromStr("7503.389830525412237884"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), }, - PositionNotional: sdk.MustNewDecFromStr("4424.999944687500580781"), - RealizedPnl: sdk.MustNewDecFromStr("-1025.000014749999852500"), - BadDebt: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 27), + PositionNotional: sdk.MustNewDecFromStr("4426.999944687500580781"), + RealizedPnl: sdk.MustNewDecFromStr("-1023.610184214580834200"), + BadDebt: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 26), FundingPayment: sdk.NewDec(2), TransactionFee: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 2), BlockHeight: 1, MarginToUser: sdk.NewInt(-2), ChangeReason: types.ChangeReason_PartialClose, - ExchangedNotional: sdk.MustNewDecFromStr("-5575.000055312499419219"), - ExchangedSize: sdk.MustNewDecFromStr("-2500.000000000000000000"), + ExchangedNotional: sdk.MustNewDecFromStr("-5573.000055312499419219"), + ExchangedSize: sdk.MustNewDecFromStr("-2496.610169474587762116"), })), TC("partial close short position with positive PnL"). @@ -1432,9 +1343,9 @@ func TestPartialClose(t *testing.T) { PositionShouldBeEqual(alice, pairBtcNusd, Position_PositionShouldBeEqualTo(types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.MustNewDecFromStr("7751.999992499999925000"), - OpenNotional: sdk.MustNewDecFromStr("2500.000001875000032812"), - Size_: sdk.MustNewDecFromStr("-2499.999999999999999995"), + Margin: sdk.MustNewDecFromStr("7733.999992789639924900"), + OpenNotional: sdk.MustNewDecFromStr("2520.000001585360032912"), + Size_: sdk.MustNewDecFromStr("-2519.999999700400001111"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), })), @@ -1442,22 +1353,22 @@ func TestPartialClose(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.MustNewDecFromStr("7751.999992499999925000"), - OpenNotional: sdk.MustNewDecFromStr("2500.000001875000032812"), - Size_: sdk.MustNewDecFromStr("-2499.999999999999999995"), + Margin: sdk.MustNewDecFromStr("7733.999992789639924900"), + OpenNotional: sdk.MustNewDecFromStr("2520.000001585360032912"), + Size_: sdk.MustNewDecFromStr("-2519.999999700400001111"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), }, - PositionNotional: sdk.MustNewDecFromStr("250.000004375000057812"), - RealizedPnl: sdk.MustNewDecFromStr("6749.999992499999925000"), + PositionNotional: sdk.MustNewDecFromStr("252.000004375000057812"), + RealizedPnl: sdk.MustNewDecFromStr("6731.999992789639924900"), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.NewDec(-2), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(2)), BlockHeight: 1, MarginToUser: sdk.NewInt(-2), ChangeReason: types.ChangeReason_PartialClose, - ExchangedNotional: sdk.MustNewDecFromStr("-9749.999995624999942188"), - ExchangedSize: sdk.MustNewDecFromStr("7500.000000000000000005"), + ExchangedNotional: sdk.MustNewDecFromStr("-9747.999995624999942188"), + ExchangedSize: sdk.MustNewDecFromStr("7480.000000299599998889"), }), ), @@ -1487,9 +1398,9 @@ func TestPartialClose(t *testing.T) { PositionShouldBeEqual(alice, pairBtcNusd, Position_PositionShouldBeEqualTo(types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.MustNewDecFromStr("626.999921249999212500"), - OpenNotional: sdk.MustNewDecFromStr("2500.000019687500344531"), - Size_: sdk.MustNewDecFromStr("-2500.000000000000000000"), + Margin: sdk.MustNewDecFromStr("627.761826160487012202"), + OpenNotional: sdk.MustNewDecFromStr("2515.238114777012544829"), + Size_: sdk.MustNewDecFromStr("-2515.238095009756009922"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), })), @@ -1497,22 +1408,22 @@ func TestPartialClose(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.MustNewDecFromStr("626.999921249999212500"), - OpenNotional: sdk.MustNewDecFromStr("2500.000019687500344531"), - Size_: sdk.MustNewDecFromStr("-2500.000000000000000000"), + Margin: sdk.MustNewDecFromStr("627.761826160487012202"), + OpenNotional: sdk.MustNewDecFromStr("2515.238114777012544829"), + Size_: sdk.MustNewDecFromStr("-2515.238095009756009922"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), }, - PositionNotional: sdk.MustNewDecFromStr("2625.000045937500607031"), - RealizedPnl: sdk.MustNewDecFromStr("-375.000078750000787500"), + PositionNotional: sdk.MustNewDecFromStr("2641.000045937500607031"), + RealizedPnl: sdk.MustNewDecFromStr("-374.238173839512987798"), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.NewDec(-2), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(16)), BlockHeight: 1, MarginToUser: sdk.NewInt(-16), ChangeReason: types.ChangeReason_PartialClose, - ExchangedNotional: sdk.MustNewDecFromStr("-7374.999954062499392969"), - ExchangedSize: sdk.MustNewDecFromStr("7500.000000000000000000"), + ExchangedNotional: sdk.MustNewDecFromStr("-7358.999954062499392969"), + ExchangedSize: sdk.MustNewDecFromStr("7484.761904990243990078"), }), ), @@ -1542,9 +1453,9 @@ func TestPartialClose(t *testing.T) { PositionShouldBeEqual(alice, pairBtcNusd, Position_PositionShouldBeEqualTo(types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.MustNewDecFromStr("326.999918249999182500"), - OpenNotional: sdk.MustNewDecFromStr("2500.000020437500357656"), - Size_: sdk.MustNewDecFromStr("-2500.000000000000000000"), + Margin: sdk.MustNewDecFromStr("328.321019307633252802"), + OpenNotional: sdk.MustNewDecFromStr("2514.678919379866287354"), + Size_: sdk.MustNewDecFromStr("-2514.678898862600792000"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), })), @@ -1552,22 +1463,22 @@ func TestPartialClose(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcNusd, TraderAddress: alice.String(), - Margin: sdk.MustNewDecFromStr("326.999918249999182500"), - OpenNotional: sdk.MustNewDecFromStr("2500.000020437500357656"), - Size_: sdk.MustNewDecFromStr("-2500.000000000000000000"), + Margin: sdk.MustNewDecFromStr("328.321019307633252802"), + OpenNotional: sdk.MustNewDecFromStr("2514.678919379866287354"), + Size_: sdk.MustNewDecFromStr("-2514.678898862600792000"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), }, - PositionNotional: sdk.MustNewDecFromStr("2725.000047687500630156"), - RealizedPnl: sdk.MustNewDecFromStr("-675.000081750000817500"), + PositionNotional: sdk.MustNewDecFromStr("2741.000047687500630156"), + RealizedPnl: sdk.MustNewDecFromStr("-673.678980692366747198"), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.NewDec(-2), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(16)), BlockHeight: 1, MarginToUser: sdk.NewInt(-16), ChangeReason: types.ChangeReason_PartialClose, - ExchangedNotional: sdk.MustNewDecFromStr("-7274.999952312499369844"), - ExchangedSize: sdk.MustNewDecFromStr("7500.000000000000000000"), + ExchangedNotional: sdk.MustNewDecFromStr("-7258.999952312499369844"), + ExchangedSize: sdk.MustNewDecFromStr("7485.321101137399208000"), }), ), @@ -1599,8 +1510,8 @@ func TestPartialClose(t *testing.T) { Pair: pairBtcNusd, TraderAddress: alice.String(), Margin: sdk.ZeroDec(), - OpenNotional: sdk.MustNewDecFromStr("2500.000021375000374062"), - Size_: sdk.MustNewDecFromStr("-2500.000000000000000000"), + OpenNotional: sdk.MustNewDecFromStr("2515.789494912333892759"), + Size_: sdk.MustNewDecFromStr("-2515.789473447617729414"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), })), @@ -1609,21 +1520,21 @@ func TestPartialClose(t *testing.T) { Pair: pairBtcNusd, TraderAddress: alice.String(), Margin: sdk.ZeroDec(), - OpenNotional: sdk.MustNewDecFromStr("2500.000021375000374062"), - Size_: sdk.MustNewDecFromStr("-2500.000000000000000000"), + OpenNotional: sdk.MustNewDecFromStr("2515.789494912333892759"), + Size_: sdk.MustNewDecFromStr("-2515.789473447617729414"), LastUpdatedBlockNumber: 1, LatestCumulativePremiumFraction: sdk.MustNewDecFromStr("0.0002"), }, - PositionNotional: sdk.MustNewDecFromStr("2850.000049875000659062"), - RealizedPnl: sdk.MustNewDecFromStr("-1050.000085500000855000"), - BadDebt: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 48), + PositionNotional: sdk.MustNewDecFromStr("2868.000049875000659062"), + RealizedPnl: sdk.MustNewDecFromStr("-1047.789559037334373697"), + BadDebt: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 46), FundingPayment: sdk.NewDec(-2), TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(18)), BlockHeight: 1, MarginToUser: sdk.NewInt(-18), ChangeReason: types.ChangeReason_PartialClose, - ExchangedNotional: sdk.MustNewDecFromStr("-7149.999950124999340938"), - ExchangedSize: sdk.MustNewDecFromStr("7500.000000000000000000"), + ExchangedNotional: sdk.MustNewDecFromStr("-7131.999950124999340938"), + ExchangedSize: sdk.MustNewDecFromStr("7484.210526552382270586"), }), ), TC("test partial closes fail"). @@ -1694,9 +1605,9 @@ func TestClosePosition(t *testing.T) { RealizedPnl: sdk.MustNewDecFromStr("9999.999800000002000000"), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.NewDec(2), - TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(40)), + TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(22)), BlockHeight: 1, - MarginToUser: sdk.NewInt(10_958), + MarginToUser: sdk.NewInt(10976), ChangeReason: types.ChangeReason_ClosePosition, ExchangedNotional: sdk.MustNewDecFromStr("-10000.000000000000000000"), ExchangedSize: sdk.MustNewDecFromStr("-10000.000000000000000000"), @@ -1741,9 +1652,9 @@ func TestClosePosition(t *testing.T) { RealizedPnl: sdk.MustNewDecFromStr("-100.000098999999010000"), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.NewDec(2), - TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(20)), + TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(2)), BlockHeight: 1, - MarginToUser: sdk.NewInt(878), + MarginToUser: sdk.NewInt(896), ChangeReason: types.ChangeReason_ClosePosition, ExchangedNotional: sdk.MustNewDecFromStr("-10000.000000000000000000"), ExchangedSize: sdk.MustNewDecFromStr("-10000.000000000000000000"), @@ -1787,18 +1698,18 @@ func TestClosePosition(t *testing.T) { LastUpdatedBlockNumber: 2, }, PositionNotional: sdk.ZeroDec(), - TransactionFee: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 18), + TransactionFee: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 0), RealizedPnl: sdk.MustNewDecFromStr("-1100.000088999999110000"), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(102)), FundingPayment: sdk.NewDec(2), BlockHeight: 2, - MarginToUser: sdk.NewInt(-18), + MarginToUser: sdk.NewInt(0), ChangeReason: types.ChangeReason_ClosePosition, ExchangedNotional: sdk.MustNewDecFromStr("-10000.000000000000000000"), ExchangedSize: sdk.MustNewDecFromStr("-10000.000000000000000000"), }), ModuleBalanceEqual(types.VaultModuleAccount, types.TestingCollateralDenomNUSD, sdk.NewInt(1102)), // 1000 + 102 from perp ef - ModuleBalanceEqual(types.PerpEFModuleAccount, types.TestingCollateralDenomNUSD, sdk.NewInt(9)), + ModuleBalanceEqual(types.PerpEFModuleAccount, types.TestingCollateralDenomNUSD, sdk.NewInt(0)), ), TC("close short position with positive PnL"). @@ -1839,9 +1750,9 @@ func TestClosePosition(t *testing.T) { RealizedPnl: sdk.MustNewDecFromStr("8999.999989999999900000"), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.NewDec(-2), - TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(2)), + TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(20)), BlockHeight: 1, - MarginToUser: sdk.NewInt(10_000), + MarginToUser: sdk.NewInt(9982), ChangeReason: types.ChangeReason_ClosePosition, ExchangedNotional: sdk.MustNewDecFromStr("-10000.000000000000000000"), ExchangedSize: sdk.MustNewDecFromStr("10000.000000000000000000"), @@ -1886,9 +1797,9 @@ func TestClosePosition(t *testing.T) { RealizedPnl: sdk.MustNewDecFromStr("-100.000101000001010000"), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.NewDec(-2), - TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(20)), + TransactionFee: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(2)), BlockHeight: 1, - MarginToUser: sdk.NewInt(882), + MarginToUser: sdk.NewInt(900), ChangeReason: types.ChangeReason_ClosePosition, ExchangedNotional: sdk.MustNewDecFromStr("-10000.000000000000000000"), ExchangedSize: sdk.MustNewDecFromStr("10000.000000000000000000"), @@ -1932,18 +1843,18 @@ func TestClosePosition(t *testing.T) { LastUpdatedBlockNumber: 2, }, PositionNotional: sdk.ZeroDec(), - TransactionFee: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 22), + TransactionFee: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 0), RealizedPnl: sdk.MustNewDecFromStr("-1100.000111000001110000"), BadDebt: sdk.NewInt64Coin(types.TestingCollateralDenomNUSD, 98), FundingPayment: sdk.NewDec(-2), BlockHeight: 2, - MarginToUser: sdk.NewInt(-22), + MarginToUser: sdk.NewInt(0), ChangeReason: types.ChangeReason_ClosePosition, ExchangedNotional: sdk.MustNewDecFromStr("-10000.000000000000000000"), ExchangedSize: sdk.MustNewDecFromStr("10000.000000000000000000"), }), ModuleBalanceEqual(types.VaultModuleAccount, types.TestingCollateralDenomNUSD, sdk.NewInt(1098)), // 1000 + 98 from perp ef - ModuleBalanceEqual(types.PerpEFModuleAccount, types.TestingCollateralDenomNUSD, sdk.NewInt(11)), + ModuleBalanceEqual(types.PerpEFModuleAccount, types.TestingCollateralDenomNUSD, sdk.NewInt(0)), ), } @@ -2002,12 +1913,12 @@ func TestUpdateSwapInvariant(t *testing.T) { ShiftSwapInvariant(pairBtcNusd, startingSwapInvariant.MulRaw(100)), AMMShouldBeEqual( pairBtcNusd, - AMM_SwapInvariantShouldBeEqual(sdk.MustNewDecFromStr("99999999999999999999999999.999999000000000000"))), + AMM_SwapInvariantShouldBeEqual(sdk.MustNewDecFromStr("100000000000000000000000000.000005462000000000"))), ClosePosition(alice, pairBtcNusd), ). Then( PositionShouldNotExist(alice, pairBtcNusd, 1), - ModuleBalanceShouldBeEqualTo(types.VaultModuleAccount, sdk.NewCoins()), + ModuleBalanceShouldBeEqualTo(types.VaultModuleAccount, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.OneInt()))), ), TC("only short position - increasing k"). Given( @@ -2022,7 +1933,7 @@ func TestUpdateSwapInvariant(t *testing.T) { ShiftSwapInvariant(pairBtcNusd, startingSwapInvariant.MulRaw(100)), AMMShouldBeEqual( pairBtcNusd, - AMM_SwapInvariantShouldBeEqual(sdk.MustNewDecFromStr("99999999999999999999999999.999999000000000000"))), + AMM_SwapInvariantShouldBeEqual(sdk.MustNewDecFromStr("99999999999999999999999999.999996174000000000"))), ClosePosition(alice, pairBtcNusd), ). Then( @@ -2045,7 +1956,7 @@ func TestUpdateSwapInvariant(t *testing.T) { startingSwapInvariant.QuoRaw(10)), AMMShouldBeEqual( pairBtcNusd, - AMM_SwapInvariantShouldBeEqual(sdk.MustNewDecFromStr("99999999999999999873578.871987715651277660"))), + AMM_SwapInvariantShouldBeEqual(sdk.MustNewDecFromStr("99999999999999999873578.871987765741755797"))), ClosePosition(alice, pairBtcNusd), ). Then( @@ -2066,7 +1977,7 @@ func TestUpdateSwapInvariant(t *testing.T) { startingSwapInvariant.QuoRaw(10)), AMMShouldBeEqual( pairBtcNusd, - AMM_SwapInvariantShouldBeEqual(sdk.MustNewDecFromStr("99999999999999999873578.871987801032774485"))), + AMM_SwapInvariantShouldBeEqual(sdk.MustNewDecFromStr("99999999999999999873578.871987864651476452"))), ClosePosition(alice, pairBtcNusd), ). Then( @@ -2093,7 +2004,7 @@ func TestUpdateSwapInvariant(t *testing.T) { AMM_BiasShouldBeEqual(sdk.ZeroDec()), AMM_SwapInvariantShouldBeEqual(sdk.MustNewDecFromStr("100000000000000000000000000.000000000000000000"))), - ModuleBalanceShouldBeEqualTo(types.VaultModuleAccount, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(20_000_000_000)))), + ModuleBalanceShouldBeEqualTo(types.VaultModuleAccount, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(19_960_000_000)))), ModuleBalanceShouldBeEqualTo(types.FeePoolModuleAccount, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(20_000_000)))), // Fees are 10_000_000_000 * 0.0010 * 2 ClosePosition(alice, pairBtcNusd), @@ -2104,7 +2015,7 @@ func TestUpdateSwapInvariant(t *testing.T) { PositionShouldNotExist(bob, pairBtcNusd, 1), ModuleBalanceShouldBeEqualTo(types.VaultModuleAccount, sdk.NewCoins()), - ModuleBalanceShouldBeEqualTo(types.PerpEFModuleAccount, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(39_782_394)))), + ModuleBalanceShouldBeEqualTo(types.PerpEFModuleAccount, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(39_960_000)))), ), TC("long and short position - reducing k"). Given( @@ -2125,7 +2036,7 @@ func TestUpdateSwapInvariant(t *testing.T) { AMM_BiasShouldBeEqual(sdk.ZeroDec()), AMM_SwapInvariantShouldBeEqual(sdk.MustNewDecFromStr("99999999999999999873578.871987712489000000"))), - ModuleBalanceShouldBeEqualTo(types.VaultModuleAccount, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(20_000_000_000)))), + ModuleBalanceShouldBeEqualTo(types.VaultModuleAccount, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(19_960_000_000)))), ModuleBalanceShouldBeEqualTo(types.FeePoolModuleAccount, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(20_000_000)))), // Fees are 10_000_000_000 * 0.0010 * 2 ClosePosition(alice, pairBtcNusd), @@ -2136,7 +2047,7 @@ func TestUpdateSwapInvariant(t *testing.T) { PositionShouldNotExist(bob, pairBtcNusd, 1), ModuleBalanceShouldBeEqualTo(types.VaultModuleAccount, sdk.NewCoins()), - ModuleBalanceShouldBeEqualTo(types.PerpEFModuleAccount, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(39_200_810)))), + ModuleBalanceShouldBeEqualTo(types.PerpEFModuleAccount, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(39_960_000)))), ), } diff --git a/x/perp/v2/keeper/margin_test.go b/x/perp/v2/keeper/margin_test.go index db99d8e65..f1cb16a80 100644 --- a/x/perp/v2/keeper/margin_test.go +++ b/x/perp/v2/keeper/margin_test.go @@ -30,7 +30,7 @@ func TestAddMargin(t *testing.T) { CreateCustomMarket(pairBtcUsdc, WithEnabled(true)), SetBlockNumber(1), SetBlockTime(startBlockTime), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(2020)))), + FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(2000)))), MarketOrder(alice, pairBtcUsdc, types.Direction_LONG, sdk.NewInt(1000), sdk.NewDec(10), sdk.ZeroDec()), ). When( @@ -42,9 +42,9 @@ func TestAddMargin(t *testing.T) { types.Position{ Pair: pairBtcUsdc, TraderAddress: alice.String(), - Size_: sdk.MustNewDecFromStr("9999.999900000001000000"), - Margin: sdk.NewDec(2000), - OpenNotional: sdk.NewDec(10000), + Size_: sdk.MustNewDecFromStr("9799.999903960000941192"), + Margin: sdk.NewDec(1980), + OpenNotional: sdk.NewDec(9800), LatestCumulativePremiumFraction: sdk.ZeroDec(), LastUpdatedBlockNumber: 2, }, @@ -53,13 +53,13 @@ func TestAddMargin(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcUsdc, TraderAddress: alice.String(), - Size_: sdk.MustNewDecFromStr("9999.999900000001000000"), - Margin: sdk.NewDec(2000), - OpenNotional: sdk.NewDec(10000), + Size_: sdk.MustNewDecFromStr("9799.999903960000941192"), + Margin: sdk.NewDec(1980), + OpenNotional: sdk.NewDec(9800), LatestCumulativePremiumFraction: sdk.ZeroDec(), LastUpdatedBlockNumber: 2, }, - PositionNotional: sdk.NewDec(10_000), + PositionNotional: sdk.NewDec(9800), RealizedPnl: sdk.ZeroDec(), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.ZeroDec(), @@ -80,7 +80,7 @@ func TestAddMargin(t *testing.T) { CreateCustomMarket(pairBtcUsdc, WithEnabled(true)), SetBlockNumber(1), SetBlockTime(startBlockTime), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(2020)))), + FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(2000)))), MarketOrder(alice, pairBtcUsdc, types.Direction_SHORT, sdk.NewInt(1000), sdk.NewDec(10), sdk.ZeroDec()), ). When( @@ -92,9 +92,9 @@ func TestAddMargin(t *testing.T) { types.Position{ Pair: pairBtcUsdc, TraderAddress: alice.String(), - Size_: sdk.MustNewDecFromStr("-10000.000100000001000000"), - Margin: sdk.NewDec(2000), - OpenNotional: sdk.NewDec(10000), + Size_: sdk.MustNewDecFromStr("-9800.000096040000941192"), + Margin: sdk.NewDec(1980), + OpenNotional: sdk.NewDec(9800), LatestCumulativePremiumFraction: sdk.ZeroDec(), LastUpdatedBlockNumber: 2, }, @@ -103,13 +103,13 @@ func TestAddMargin(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcUsdc, TraderAddress: alice.String(), - Size_: sdk.MustNewDecFromStr("-10000.000100000001000000"), - Margin: sdk.NewDec(2000), - OpenNotional: sdk.NewDec(10000), + Size_: sdk.MustNewDecFromStr("-9800.000096040000941192"), + Margin: sdk.NewDec(1980), + OpenNotional: sdk.NewDec(9800), LatestCumulativePremiumFraction: sdk.ZeroDec(), LastUpdatedBlockNumber: 2, }, - PositionNotional: sdk.NewDec(10_000), + PositionNotional: sdk.NewDec(9800), RealizedPnl: sdk.ZeroDec(), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.ZeroDec(), @@ -162,7 +162,7 @@ func TestRemoveMargin(t *testing.T) { CreateCustomMarket(pairBtcUsdc, WithEnabled(true)), SetBlockNumber(1), SetBlockTime(startBlockTime), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1002)))), + FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1000)))), MarketOrder(alice, pairBtcUsdc, types.Direction_LONG, sdk.NewInt(1000), sdk.OneDec(), sdk.ZeroDec()), ). When( @@ -173,9 +173,9 @@ func TestRemoveMargin(t *testing.T) { PositionShouldBeEqual(alice, pairBtcUsdc, Position_PositionShouldBeEqualTo(types.Position{ Pair: pairBtcUsdc, TraderAddress: alice.String(), - Size_: sdk.MustNewDecFromStr("999.999999000000001000"), - Margin: sdk.NewDec(500), - OpenNotional: sdk.NewDec(1000), + Size_: sdk.MustNewDecFromStr("997.999999003996000994"), + Margin: sdk.NewDec(498), + OpenNotional: sdk.NewDec(998), LatestCumulativePremiumFraction: sdk.ZeroDec(), LastUpdatedBlockNumber: 2, })), @@ -183,13 +183,13 @@ func TestRemoveMargin(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcUsdc, TraderAddress: alice.String(), - Size_: sdk.MustNewDecFromStr("999.999999000000001000"), - Margin: sdk.NewDec(500), - OpenNotional: sdk.NewDec(1000), + Size_: sdk.MustNewDecFromStr("997.999999003996000994"), + Margin: sdk.NewDec(498), + OpenNotional: sdk.NewDec(998), LatestCumulativePremiumFraction: sdk.ZeroDec(), LastUpdatedBlockNumber: 2, }, - PositionNotional: sdk.NewDec(1000), + PositionNotional: sdk.NewDec(998), RealizedPnl: sdk.ZeroDec(), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.ZeroDec(), @@ -210,20 +210,20 @@ func TestRemoveMargin(t *testing.T) { CreateCustomMarket(pairBtcUsdc, WithEnabled(true)), SetBlockNumber(1), SetBlockTime(startBlockTime), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1002)))), + FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1000)))), MarketOrder(alice, pairBtcUsdc, types.Direction_LONG, sdk.NewInt(1000), sdk.OneDec(), sdk.ZeroDec()), MoveToNextBlock(), ). When( - RemoveMarginFail(alice, pairBtcUsdc, sdk.NewInt(999), types.ErrMarginRatioTooLow), + RemoveMarginFail(alice, pairBtcUsdc, sdk.NewInt(997), types.ErrMarginRatioTooLow), ). Then( PositionShouldBeEqual(alice, pairBtcUsdc, Position_PositionShouldBeEqualTo(types.Position{ Pair: pairBtcUsdc, TraderAddress: alice.String(), - Size_: sdk.MustNewDecFromStr("999.999999000000001000"), - Margin: sdk.NewDec(1000), - OpenNotional: sdk.NewDec(1000), + Size_: sdk.MustNewDecFromStr("997.999999003996000994"), + Margin: sdk.NewDec(998), + OpenNotional: sdk.NewDec(998), LatestCumulativePremiumFraction: sdk.ZeroDec(), LastUpdatedBlockNumber: 1, })), @@ -237,7 +237,7 @@ func TestRemoveMargin(t *testing.T) { CreateCustomMarket(pairBtcUsdc, WithEnabled(true)), SetBlockNumber(1), SetBlockTime(startBlockTime), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1002)))), + FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1000)))), MarketOrder(alice, pairBtcUsdc, types.Direction_SHORT, sdk.NewInt(1000), sdk.OneDec(), sdk.ZeroDec()), ). When( @@ -248,9 +248,9 @@ func TestRemoveMargin(t *testing.T) { PositionShouldBeEqual(alice, pairBtcUsdc, Position_PositionShouldBeEqualTo(types.Position{ Pair: pairBtcUsdc, TraderAddress: alice.String(), - Size_: sdk.MustNewDecFromStr("-1000.000001000000001000"), - Margin: sdk.NewDec(500), - OpenNotional: sdk.NewDec(1000), + Size_: sdk.MustNewDecFromStr("-998.000000996004000994"), + Margin: sdk.NewDec(498), + OpenNotional: sdk.NewDec(998), LatestCumulativePremiumFraction: sdk.ZeroDec(), LastUpdatedBlockNumber: 2, })), @@ -258,13 +258,13 @@ func TestRemoveMargin(t *testing.T) { FinalPosition: types.Position{ Pair: pairBtcUsdc, TraderAddress: alice.String(), - Size_: sdk.MustNewDecFromStr("-1000.000001000000001000"), - Margin: sdk.NewDec(500), - OpenNotional: sdk.NewDec(1000), + Size_: sdk.MustNewDecFromStr("-998.000000996004000994"), + Margin: sdk.NewDec(498), + OpenNotional: sdk.NewDec(998), LatestCumulativePremiumFraction: sdk.ZeroDec(), LastUpdatedBlockNumber: 2, }, - PositionNotional: sdk.NewDec(1000), + PositionNotional: sdk.NewDec(998), RealizedPnl: sdk.ZeroDec(), BadDebt: sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.ZeroInt()), FundingPayment: sdk.ZeroDec(), @@ -285,20 +285,20 @@ func TestRemoveMargin(t *testing.T) { CreateCustomMarket(pairBtcUsdc, WithEnabled(true)), SetBlockNumber(1), SetBlockTime(startBlockTime), - FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1002)))), + FundAccount(alice, sdk.NewCoins(sdk.NewCoin(types.TestingCollateralDenomNUSD, sdk.NewInt(1000)))), MarketOrder(alice, pairBtcUsdc, types.Direction_SHORT, sdk.NewInt(1000), sdk.OneDec(), sdk.ZeroDec()), MoveToNextBlock(), ). When( - RemoveMarginFail(alice, pairBtcUsdc, sdk.NewInt(999), types.ErrMarginRatioTooLow), + RemoveMarginFail(alice, pairBtcUsdc, sdk.NewInt(997), types.ErrMarginRatioTooLow), ). Then( PositionShouldBeEqual(alice, pairBtcUsdc, Position_PositionShouldBeEqualTo(types.Position{ Pair: pairBtcUsdc, TraderAddress: alice.String(), - Size_: sdk.MustNewDecFromStr("-1000.000001000000001000"), - Margin: sdk.NewDec(1000), - OpenNotional: sdk.NewDec(1000), + Size_: sdk.MustNewDecFromStr("-998.000000996004000994"), + Margin: sdk.NewDec(998), + OpenNotional: sdk.NewDec(998), LatestCumulativePremiumFraction: sdk.ZeroDec(), LastUpdatedBlockNumber: 1, })), diff --git a/x/perp/v2/keeper/msg_server.go b/x/perp/v2/keeper/msg_server.go index 03ad6830b..650526b41 100644 --- a/x/perp/v2/keeper/msg_server.go +++ b/x/perp/v2/keeper/msg_server.go @@ -126,6 +126,7 @@ func (m msgServer) SettlePosition(ctx context.Context, msg *types.MsgSettlePosit }, nil } +// DonateToEcosystemFund allows users to donate to the ecosystem fund. func (m msgServer) DonateToEcosystemFund(ctx context.Context, msg *types.MsgDonateToEcosystemFund) (*types.MsgDonateToEcosystemFundResponse, error) { if err := m.k.BankKeeper.SendCoinsFromAccountToModule( sdk.UnwrapSDKContext(ctx), @@ -139,7 +140,7 @@ func (m msgServer) DonateToEcosystemFund(ctx context.Context, msg *types.MsgDona return &types.MsgDonateToEcosystemFundResponse{}, nil } -// ChangeCollateralDenom: Updates the collateral denom. A denom is valid if it is +// ChangeCollateralDenom Updates the collateral denom. A denom is valid if it is // possible to make an sdk.Coin using it. [Admin] Only callable by sudoers. func (m msgServer) ChangeCollateralDenom( goCtx context.Context, txMsg *types.MsgChangeCollateralDenom, diff --git a/x/perp/v2/keeper/position.go b/x/perp/v2/keeper/position.go index da9643fbb..52d5d9fe4 100644 --- a/x/perp/v2/keeper/position.go +++ b/x/perp/v2/keeper/position.go @@ -9,6 +9,7 @@ import ( "github.com/NibiruChain/nibiru/x/perp/v2/types" ) +// GetPosition returns the position or types.ErrPositionNotFound if it does not exist. func (k Keeper) GetPosition(ctx sdk.Context, pair asset.Pair, version uint64, account sdk.AccAddress) (types.Position, error) { position, err := k.Positions.Get(ctx, collections.Join(collections.Join(pair, version), account)) if err != nil { diff --git a/x/perp/v2/keeper/settlement.go b/x/perp/v2/keeper/settlement.go index 970cd3a37..5396be2b3 100644 --- a/x/perp/v2/keeper/settlement.go +++ b/x/perp/v2/keeper/settlement.go @@ -27,7 +27,7 @@ func (k Keeper) SettlePosition(ctx sdk.Context, pair asset.Pair, version uint64, return } - updatedAMM, positionResp, err := k.settlePosition(ctx, market, amm, position) + _, positionResp, err := k.settlePosition(ctx, market, amm, position) if err != nil { return } @@ -45,10 +45,10 @@ func (k Keeper) SettlePosition(ctx sdk.Context, pair asset.Pair, version uint64, if err = k.afterPositionUpdate( ctx, market, - *updatedAMM, traderAddr, *positionResp, types.ChangeReason_Settlement, + sdk.ZeroInt(), position, ); err != nil { return nil, err diff --git a/x/perp/v2/keeper/settlement_test.go b/x/perp/v2/keeper/settlement_test.go index 2da09148d..c1368f986 100644 --- a/x/perp/v2/keeper/settlement_test.go +++ b/x/perp/v2/keeper/settlement_test.go @@ -76,7 +76,7 @@ func TestSettlePosition(t *testing.T) { sdk.NewDec(10), sdk.ZeroDec(), ), - QueryPosition(pairBtcUsdc, alice, QueryPosition_MarginRatioEquals(sdk.MustNewDecFromStr("-0.093502230451982156"))), + QueryPosition(pairBtcUsdc, alice, QueryPosition_MarginRatioEquals(sdk.MustNewDecFromStr("-0.090096188479034643"))), ).When( // Alice opened a short position (leverage x10) while bob a bigger long position // Price jumped by 10%, with a settlement price of 1.09 @@ -100,22 +100,22 @@ func TestSettlePosition(t *testing.T) { LastUpdatedBlockNumber: 1, }, ), - SettlePositionChecker_MarginToVault(sdk.ZeroDec()), - SettlePositionChecker_BadDebt(sdk.MustNewDecFromStr("1.010101010101010101")), + SettlePositionChecker_MarginToVault(sdk.MustNewDecFromStr("-1.009493031710765502")), + SettlePositionChecker_BadDebt(sdk.ZeroDec()), ), SettlePosition( pairBtcUsdc, 1, bob, - SettlePositionChecker_MarginToVault(sdk.MustNewDecFromStr("-1101.010101010101010100")), + SettlePositionChecker_MarginToVault(sdk.MustNewDecFromStr("-1076.990506968289234498")), SettlePositionChecker_BadDebt(sdk.ZeroDec()), ), ).Then( PositionShouldNotExist(alice, pairBtcUsdc, 1), PositionShouldNotExist(bob, pairBtcUsdc, 1), SetBlockNumber(2), - BalanceEqual(alice, types.TestingCollateralDenomNUSD, sdk.NewInt(0)), - BalanceEqual(bob, types.TestingCollateralDenomNUSD, sdk.NewInt(1101-20)), + BalanceEqual(alice, types.TestingCollateralDenomNUSD, sdk.NewInt(5)), + BalanceEqual(bob, types.TestingCollateralDenomNUSD, sdk.NewInt(1095)), ), TC("Error: can't settle on enabled market").When( diff --git a/x/perp/v2/types/amm.go b/x/perp/v2/types/amm.go index 4eaef67a4..d679bf220 100644 --- a/x/perp/v2/types/amm.go +++ b/x/perp/v2/types/amm.go @@ -305,7 +305,7 @@ func (amm *AMM) SwapBaseAsset(baseAssetAmt sdk.Dec, dir Direction) (quoteAssetDe return amm.QuoteReserveToAsset(quoteReserveDelta), nil } -// Bias: returns the bias, or open interest skew, of the market in the base +// Bias returns the bias, or open interest skew, of the market in the base // units. Bias is the net amount of long perpetual contracts minus the net // amount of shorts. func (amm *AMM) Bias() (bias sdk.Dec) { @@ -347,7 +347,7 @@ func (amm AMM) CalcRepegCost(newPriceMultiplier sdk.Dec) (cost sdkmath.Int, err return costDec.Ceil().TruncateInt(), nil } -// returns the amount of quote assets the amm has to pay out if all longs and shorts close out their positions +// GetMarketValue returns the amount of quote assets the amm has to pay out if all longs and shorts close out their positions // positive value means the amm has to pay out quote assets // negative value means the amm has to receive quote assets func (amm AMM) GetMarketValue() (sdk.Dec, error) {