Skip to content

Commit

Permalink
Address Gimeno PR comments + more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Unique-Divine committed Nov 29, 2023
1 parent 552a2d5 commit fe1fe03
Show file tree
Hide file tree
Showing 13 changed files with 178 additions and 134 deletions.
2 changes: 2 additions & 0 deletions proto/nibiru/perp/v2/event.proto
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ message MarketUpdatedEvent {
nibiru.perp.v2.Market final_market = 1 [ (gogoproto.nullable) = false ];
}

// EventShiftPegMultiplier: ABCI event emitted from MsgShiftPegMultiplier
message EventShiftPegMultiplier {
string old_peg_multiplier = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
Expand All @@ -247,6 +248,7 @@ message EventShiftPegMultiplier {
cosmos.base.v1beta1.Coin cost_paid = 3 [ (gogoproto.nullable) = false ];
}

// EventShiftSwapInvariant: ABCI event emitted from MsgShiftSwapInvariant
message EventShiftSwapInvariant {
string old_swap_invariant = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
Expand Down
10 changes: 6 additions & 4 deletions proto/nibiru/perp/v2/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ service Msg {
rpc DonateToEcosystemFund(MsgDonateToEcosystemFund)
returns (MsgDonateToEcosystemFundResponse) {}

// 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.
rpc ChangeCollateralDenom(MsgChangeCollateralDenom)
returns (MsgChangeCollateralDenomResponse) {}

Expand All @@ -38,13 +40,13 @@ service Msg {
rpc WithdrawEpochRebates(MsgWithdrawEpochRebates)
returns (MsgWithdrawEpochRebatesResponse) {}

// ShiftPegMultiplier: gRPC tx msg for changing the peg multiplier.
// Admin-only.
// ShiftPegMultiplier: gRPC tx msg for changing a market's peg multiplier.
// [Admin] Only callable by sudoers.
rpc ShiftPegMultiplier(MsgShiftPegMultiplier)
returns (MsgShiftPegMultiplierResponse) {}

// ShiftSwapInvariant: gRPC tx msg for changing the swap invariant.
// Admin-only.
// ShiftSwapInvariant: gRPC tx msg for changing a market's swap invariant.
// [Admin] Only callable by sudoers.
rpc ShiftSwapInvariant(MsgShiftSwapInvariant)
returns (MsgShiftSwapInvariantResponse) {}
}
Expand Down
17 changes: 17 additions & 0 deletions x/common/testutil/testapp/testapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
epochstypes "github.com/NibiruChain/nibiru/x/epochs/types"
inflationtypes "github.com/NibiruChain/nibiru/x/inflation/types"
"github.com/NibiruChain/nibiru/x/perp/v2/types"
sudotypes "github.com/NibiruChain/nibiru/x/sudo/types"
)

// NewNibiruTestAppAndContext creates an 'app.NibiruApp' instance with an
Expand All @@ -36,17 +37,33 @@ func NewNibiruTestAppAndContext() (*app.NibiruApp, sdk.Context) {
app.OracleKeeper.SetPrice(ctx, "xxx:yyy", sdk.NewDec(20000))

app.PerpKeeperV2.Collateral.Set(ctx, types.TestingCollateralDenomNUSD)
app.SudoKeeper.Sudoers.Set(ctx, DefaultSudoers())

return app, ctx
}

// NewContext: Returns a fresh sdk.Context corresponding to the given NibiruApp.
func NewContext(nibiru *app.NibiruApp) sdk.Context {
return nibiru.NewContext(false, tmproto.Header{
Height: 1,
Time: time.Now().UTC(),
})
}

// DefaultSudoers: State for the x/sudo module for the default test app.
func DefaultSudoers() sudotypes.Sudoers {
EnsureNibiruPrefix()
addr := DefaultSudoRoot().String()
return sudotypes.Sudoers{
Root: addr,
Contracts: []string{addr},
}
}

func DefaultSudoRoot() sdk.AccAddress {
return sdk.MustAccAddressFromBech32("nibi1zaavvzxez0elundtn32qnk9lkm8kmcsz44g7xl")
}

// NewNibiruTestAppAndZeroTimeCtx: Runs NewNibiruTestAppAndZeroTimeCtx with the
// block time set to time zero.
func NewNibiruTestAppAndContextAtTime(startTime time.Time) (*app.NibiruApp, sdk.Context) {
Expand Down
29 changes: 23 additions & 6 deletions x/perp/v2/integration/action/dnr.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/NibiruChain/nibiru/app"
"github.com/NibiruChain/nibiru/x/common/asset"
"github.com/NibiruChain/nibiru/x/common/testutil/action"
perpkeeper "github.com/NibiruChain/nibiru/x/perp/v2/keeper"
"github.com/NibiruChain/nibiru/x/perp/v2/types"
)

Expand Down Expand Up @@ -216,16 +217,20 @@ func (s *setCustomDiscountAction) Do(app *app.NibiruApp, ctx sdk.Context) (outCt
}

type fundDnREpoch struct {
amt sdk.Coins
funds sdk.Coins
}

func (f fundDnREpoch) Do(app *app.NibiruApp, ctx sdk.Context) (outCtx sdk.Context, err error, isMandatory bool) {
tmpAcc := testutil.AccAddress()
ctx, err, _ = action.FundAccount(tmpAcc, f.amt).Do(app, ctx)
ctx, err, _ = action.FundAccount(tmpAcc, f.funds).Do(app, ctx)
if err != nil {
return ctx, err, true
}
_, err = app.PerpKeeperV2.AllocateEpochRebates(ctx, tmpAcc, f.amt)
_, err = perpkeeper.NewMsgServerImpl(app.PerpKeeperV2).AllocateEpochRebates(
ctx, &types.MsgAllocateEpochRebates{
Sender: tmpAcc.String(),
Rebates: f.funds,
})
if err != nil {
return ctx, err, true
}
Expand Down Expand Up @@ -261,10 +266,15 @@ type dnrRebateIsAction struct {
}

func (d dnrRebateIsAction) Do(app *app.NibiruApp, ctx sdk.Context) (outCtx sdk.Context, err error, isMandatory bool) {
withdrawn, err := app.PerpKeeperV2.WithdrawEpochRebates(ctx, d.epoch, d.user)
resp, err := perpkeeper.NewMsgServerImpl(app.PerpKeeperV2).WithdrawEpochRebates(
ctx, &types.MsgWithdrawEpochRebates{
Sender: d.user.String(),
Epochs: []uint64{d.epoch},
})
if err != nil {
return ctx, err, true
}
withdrawn := resp.WithdrawnRebates
if !withdrawn.IsEqual(d.expectedRewards) {
return ctx, fmt.Errorf("expected %s, got %s", d.expectedRewards, withdrawn), true
}
Expand All @@ -291,9 +301,16 @@ type dnrRebateFailsAction struct {
epoch uint64
}

func (d dnrRebateFailsAction) Do(app *app.NibiruApp, ctx sdk.Context) (outCtx sdk.Context, err error, isMandatory bool) {
withdrawn, err := app.PerpKeeperV2.WithdrawEpochRebates(ctx, d.epoch, d.user)
func (d dnrRebateFailsAction) Do(
app *app.NibiruApp, ctx sdk.Context,
) (outCtx sdk.Context, err error, isMandatory bool) {
resp, err := perpkeeper.NewMsgServerImpl(app.PerpKeeperV2).WithdrawEpochRebates(
ctx, &types.MsgWithdrawEpochRebates{
Sender: d.user.String(),
Epochs: []uint64{d.epoch},
})
if err == nil {
withdrawn := resp.WithdrawnRebates
return ctx, fmt.Errorf("expected withdrawal error but got instead: %s rewards", withdrawn.String()), true
}
return ctx, nil, true
Expand Down
9 changes: 7 additions & 2 deletions x/perp/v2/integration/action/market.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/NibiruChain/nibiru/x/common"
"github.com/NibiruChain/nibiru/x/common/asset"
"github.com/NibiruChain/nibiru/x/common/testutil/action"
"github.com/NibiruChain/nibiru/x/common/testutil/testapp"

"github.com/NibiruChain/nibiru/app"
"github.com/NibiruChain/nibiru/x/perp/v2/keeper"
Expand Down Expand Up @@ -140,7 +141,9 @@ type shiftPegMultiplier struct {
}

func (e shiftPegMultiplier) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, error, bool) {
err := app.PerpKeeperV2.UnsafeShiftPegMultiplier(ctx, e.pair, e.newValue)
err := app.PerpKeeperV2.Admin.ShiftPegMultiplier(
ctx, e.pair, e.newValue, testapp.DefaultSudoRoot(),
)
return ctx, err, true
}

Expand All @@ -157,7 +160,9 @@ type shiftSwapInvariant struct {
}

func (e shiftSwapInvariant) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, error, bool) {
err := app.PerpKeeperV2.UnsafeShiftSwapInvariant(ctx, e.pair, e.newValue)
err := app.PerpKeeperV2.Admin.ShiftSwapInvariant(
ctx, e.pair, e.newValue, testapp.DefaultSudoRoot(),
)
return ctx, err, true
}

Expand Down
20 changes: 18 additions & 2 deletions x/perp/v2/integration/action/position.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/NibiruChain/nibiru/x/common/denoms"
"github.com/NibiruChain/nibiru/x/common/testutil"
"github.com/NibiruChain/nibiru/x/common/testutil/action"
perpkeeper "github.com/NibiruChain/nibiru/x/perp/v2/keeper"
"github.com/NibiruChain/nibiru/x/perp/v2/types"
)

Expand Down Expand Up @@ -343,7 +344,14 @@ type partialClose struct {
}

func (p partialClose) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, error, bool) {
_, err := app.PerpKeeperV2.PartialClose(ctx, p.pair, p.trader, p.amount)
txMsg := &types.MsgPartialClose{
Sender: p.trader.String(),
Pair: p.pair,
Size_: p.amount,
}
goCtx := sdk.WrapSDKContext(ctx)
_, err := perpkeeper.NewMsgServerImpl(app.PerpKeeperV2).PartialClose(
goCtx, txMsg)
if err != nil {
return ctx, err, true
}
Expand All @@ -368,7 +376,15 @@ type partialCloseFails struct {
}

func (p partialCloseFails) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, error, bool) {
_, err := app.PerpKeeperV2.PartialClose(ctx, p.pair, p.trader, p.amount)
txMsg := &types.MsgPartialClose{
Sender: p.trader.String(),
Pair: p.pair,
Size_: p.amount,
}
goCtx := sdk.WrapSDKContext(ctx)
_, err := perpkeeper.NewMsgServerImpl(app.PerpKeeperV2).PartialClose(
goCtx, txMsg,
)

if !errors.Is(err, p.expectedErr) {
return ctx, fmt.Errorf("expected error %s, got %s", p.expectedErr, err), false
Expand Down
61 changes: 59 additions & 2 deletions x/perp/v2/keeper/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,38 @@ func (k admin) ShiftPegMultiplier(
if err := k.SudoKeeper.CheckPermissions(sender, ctx); err != nil {
return err
}
return k.UnsafeShiftPegMultiplier(ctx, pair, newPriceMultiplier)

amm, err := k.GetAMM(ctx, pair)
if err != nil {
return err
}
oldPriceMult := amm.PriceMultiplier

if newPriceMultiplier.Equal(oldPriceMult) {
// same price multiplier, no-op
return nil
}

// Compute cost of re-pegging the pool
cost, err := amm.CalcRepegCost(newPriceMultiplier)
if err != nil {
return err
}

costPaid, err := k.handleMarketUpdateCost(ctx, pair, cost)
if err != nil {
return err
}

// Do the re-peg
amm.PriceMultiplier = newPriceMultiplier
k.SaveAMM(ctx, amm)

return ctx.EventManager().EmitTypedEvent(&types.EventShiftPegMultiplier{
OldPegMultiplier: oldPriceMult,
NewPegMultiplier: newPriceMultiplier,
CostPaid: costPaid,
})
}

// ShiftSwapInvariant: Edit the swap invariant (liquidity depth) of an amm pool,
Expand All @@ -202,5 +233,31 @@ func (k admin) ShiftSwapInvariant(
if err := k.SudoKeeper.CheckPermissions(sender, ctx); err != nil {
return err
}
return k.UnsafeShiftSwapInvariant(ctx, pair, newSwapInvariant)
amm, err := k.GetAMM(ctx, pair)
if err != nil {
return err
}

cost, err := amm.CalcUpdateSwapInvariantCost(newSwapInvariant.ToLegacyDec())
if err != nil {
return err
}

costPaid, err := k.handleMarketUpdateCost(ctx, pair, cost)
if err != nil {
return err
}

err = amm.UpdateSwapInvariant(newSwapInvariant.ToLegacyDec())
if err != nil {
return err
}

k.SaveAMM(ctx, amm)

return ctx.EventManager().EmitTypedEvent(&types.EventShiftSwapInvariant{
OldSwapInvariant: amm.BaseReserve.Mul(amm.QuoteReserve).RoundInt(),
NewSwapInvariant: newSwapInvariant,
CostPaid: costPaid,
})
}
79 changes: 0 additions & 79 deletions x/perp/v2/keeper/amm.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,85 +11,6 @@ import (
types "github.com/NibiruChain/nibiru/x/perp/v2/types"
)

// UnsafeShiftPegMultiplier: [Without checking x/sudo permissions] Edits the peg
// multiplier of an amm pool after making sure there's enough money in the perp
// EF fund to pay for the repeg. These funds get send to the vault to pay for
// trader's new net margin.
func (k Keeper) UnsafeShiftPegMultiplier(
ctx sdk.Context,
pair asset.Pair,
newPriceMultiplier sdk.Dec,
) (err error) {
amm, err := k.GetAMM(ctx, pair)
if err != nil {
return err
}
oldPriceMult := amm.PriceMultiplier

if newPriceMultiplier.Equal(oldPriceMult) {
// same price multiplier, no-op
return nil
}

// Compute cost of re-pegging the pool
cost, err := amm.CalcRepegCost(newPriceMultiplier)
if err != nil {
return err
}

costPaid, err := k.handleMarketUpdateCost(ctx, pair, cost)
if err != nil {
return err
}

// Do the re-peg
amm.PriceMultiplier = newPriceMultiplier
k.SaveAMM(ctx, amm)

return ctx.EventManager().EmitTypedEvent(&types.EventShiftPegMultiplier{
OldPegMultiplier: oldPriceMult,
NewPegMultiplier: newPriceMultiplier,
CostPaid: costPaid,
})
}

// UnsafeShiftSwapInvariant: [Without checking x/sudo permissions] Edit the swap
// invariant of an amm pool after making sure there's enough money in the perp
// fund to pay for the operation. These funds get send to the vault to pay for
// trader's new net margin.
func (k Keeper) UnsafeShiftSwapInvariant(
ctx sdk.Context, pair asset.Pair, newSwapInvariant sdkmath.Int,
) (err error) {
// Get the pool
amm, err := k.GetAMM(ctx, pair)
if err != nil {
return err
}

cost, err := amm.CalcUpdateSwapInvariantCost(newSwapInvariant.ToLegacyDec())
if err != nil {
return err
}

costPaid, err := k.handleMarketUpdateCost(ctx, pair, cost)
if err != nil {
return err
}

err = amm.UpdateSwapInvariant(newSwapInvariant.ToLegacyDec())
if err != nil {
return err
}

k.SaveAMM(ctx, amm)

return ctx.EventManager().EmitTypedEvent(&types.EventShiftSwapInvariant{
OldSwapInvariant: amm.BaseReserve.Mul(amm.QuoteReserve).RoundInt(),
NewSwapInvariant: newSwapInvariant,
CostPaid: costPaid,
})
}

func (k Keeper) handleMarketUpdateCost(
ctx sdk.Context, pair asset.Pair, costAmt sdkmath.Int,
) (costPaid sdk.Coin, err error) {
Expand Down
Loading

0 comments on commit fe1fe03

Please sign in to comment.