Skip to content

Commit

Permalink
feat: create settle position function (#1632)
Browse files Browse the repository at this point in the history
* feat: create settle position function

* feat: wire settlement cmd

* nit: changelog

* fix: fix command count

* fix: fix settlement pnl calculation

* fix: more tests
  • Loading branch information
matthiasmatt authored Oct 18, 2023
1 parent b4e4a4c commit 4561f47
Show file tree
Hide file tree
Showing 17 changed files with 1,031 additions and 139 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#1607](https://github.com/NibiruChain/nibiru/pull/1607) - Token factory transaction messages for CreateDenom, ChangeAdmin, and UpdateModuleParams
* [#1620](https://github.com/NibiruChain/nibiru/pull/1620) - Token factory transaction messages for Mint and Burn
* [#1573](https://github.com/NibiruChain/nibiru/pull/1573) - feat(perp): Close markets and compute settlement price
* [#1632](https://github.com/NibiruChain/nibiru/pull/1632) - feat(perp): Add settle position transaction

### State Machine Breaking

Expand Down
17 changes: 17 additions & 0 deletions proto/nibiru/perp/v2/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,27 @@ service Msg {

rpc PartialClose(MsgPartialClose) returns (MsgPartialCloseResponse) {}

rpc SettlePosition(MsgSettlePosition) returns (MsgClosePositionResponse) {}

rpc DonateToEcosystemFund(MsgDonateToEcosystemFund)
returns (MsgDonateToEcosystemFundResponse) {}
}

// -------------------------- Settle Position --------------------------

/* MsgSettlePosition: Msg to remove margin. */
message MsgSettlePosition {
string sender = 1;

string pair = 2 [
(gogoproto.customtype) =
"github.com/NibiruChain/nibiru/x/common/asset.Pair",
(gogoproto.nullable) = false
];

uint64 version = 3;
}

// -------------------------- RemoveMargin --------------------------

/* MsgRemoveMargin: Msg to remove margin. */
Expand Down
2 changes: 0 additions & 2 deletions x/perp/v2/client/cli/gen_market.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,6 @@ func newMarketFromFlags(flagSet *flag.FlagSet,
return types.Market{}, types.AMM{}, err
}

fmt.Println(maxFundingRate)

priceMultiplier, err := sdk.NewDecFromStr(priceMultiplierStr)
if err != nil {
return types.Market{}, types.AMM{}, err
Expand Down
46 changes: 46 additions & 0 deletions x/perp/v2/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cli

import (
"fmt"
"strconv"
"strings"

"github.com/cosmos/cosmos-sdk/client"
Expand Down Expand Up @@ -29,6 +30,7 @@ func GetTxCmd() *cobra.Command {
AddMarginCmd(),
MarketOrderCmd(),
ClosePositionCmd(),
SettlePositionCmd(),
PartialCloseCmd(),
MultiLiquidateCmd(),
DonateToEcosystemFundCmd(),
Expand Down Expand Up @@ -315,6 +317,50 @@ func AddMarginCmd() *cobra.Command {
return cmd
}

func SettlePositionCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "settle [market] [version]",
Short: "Settle position in a specific market version when the market is disabled",
Long: strings.TrimSpace(
fmt.Sprintf(`
$ %s tx perp settle osmo:nusd 1
`, version.AppName),
),
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

version, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return err
}

pair, err := asset.TryNewPair(args[0])
if err != nil {
return err
}

msg := &types.MsgSettlePosition{
Sender: clientCtx.GetFromAddress().String(),
Pair: pair,
Version: version,
}
if err = msg.ValidateBasic(); err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

func DonateToEcosystemFundCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "donate-ef [amount]",
Expand Down
5 changes: 1 addition & 4 deletions x/perp/v2/integration/action/market.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package action

import (
"fmt"

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

Expand All @@ -21,7 +19,6 @@ type logger struct {
}

func (e logger) Do(_ *app.NibiruApp, ctx sdk.Context) (sdk.Context, error, bool) {
fmt.Println(e.log)
return ctx, nil, true
}

Expand All @@ -38,7 +35,7 @@ type createMarketAction struct {
}

func (c createMarketAction) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, error, bool) {
app.PerpKeeperV2.MarketLastVersion.Insert(ctx, c.Market.Pair, types.MarketLastVersion{Version: 1})
app.PerpKeeperV2.MarketLastVersion.Insert(ctx, c.Market.Pair, types.MarketLastVersion{Version: c.Market.Version})
app.PerpKeeperV2.SaveMarket(ctx, c.Market)
app.PerpKeeperV2.SaveAMM(ctx, c.AMM)

Expand Down
97 changes: 97 additions & 0 deletions x/perp/v2/integration/action/settlement.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package action

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/NibiruChain/nibiru/app"
"github.com/NibiruChain/nibiru/x/common/asset"
"github.com/NibiruChain/nibiru/x/common/testutil/action"
"github.com/NibiruChain/nibiru/x/perp/v2/types"
)

// closeMarket
type closeMarket struct {
pair asset.Pair
}
Expand All @@ -24,3 +28,96 @@ func (c closeMarket) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, error
func CloseMarket(pair asset.Pair) action.Action {
return closeMarket{pair: pair}
}

// closeMarketShouldFail
type closeMarketShouldFail struct {
pair asset.Pair
}

func (c closeMarketShouldFail) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, error, bool) {
err := app.PerpKeeperV2.CloseMarket(ctx, c.pair)
if err == nil {
return ctx, err, false
}

return ctx, nil, true
}

func CloseMarketShouldFail(pair asset.Pair) action.Action {
return closeMarketShouldFail{pair: pair}
}

// settlePosition
type settlePosition struct {
pair asset.Pair
version uint64
trader sdk.AccAddress
responseCheckers []SettlePositionChecker
}

func (c settlePosition) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, error, bool) {
resp, err := app.PerpKeeperV2.SettlePosition(ctx, c.pair, c.version, c.trader)
if err != nil {
return ctx, err, false
}

for _, checker := range c.responseCheckers {
if err := checker(*resp); err != nil {
return ctx, err, false
}
}

return ctx, nil, true
}

func SettlePosition(pair asset.Pair, version uint64, trader sdk.AccAddress, responseCheckers ...SettlePositionChecker) action.Action {
return settlePosition{pair: pair, version: version, trader: trader, responseCheckers: responseCheckers}
}

type SettlePositionChecker func(resp types.PositionResp) error

func SettlePositionChecker_PositionEquals(expected types.Position) SettlePositionChecker {
return func(resp types.PositionResp) error {
return types.PositionsAreEqual(&expected, &resp.Position)
}
}

func SettlePositionChecker_MarginToVault(expectedMarginToVault sdk.Dec) SettlePositionChecker {
return func(resp types.PositionResp) error {
if expectedMarginToVault.Equal(resp.MarginToVault) {
return nil
} else {
return fmt.Errorf("expected margin to vault %s, got %s", expectedMarginToVault, resp.MarginToVault)
}
}
}

func SettlePositionChecker_BadDebt(expectedBadDebt sdk.Dec) SettlePositionChecker {
return func(resp types.PositionResp) error {
if expectedBadDebt.Equal(resp.BadDebt) {
return nil
} else {
return fmt.Errorf("expected bad debt %s, got %s", expectedBadDebt, resp.BadDebt)
}
}
}

// settlePositionShouldFail
type settlePositionShouldFail struct {
pair asset.Pair
version uint64
trader sdk.AccAddress
}

func (c settlePositionShouldFail) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, error, bool) {
_, err := app.PerpKeeperV2.SettlePosition(ctx, c.pair, c.version, c.trader)
if err == nil {
return ctx, err, false
}

return ctx, nil, true
}

func SettlePositionShouldFail(pair asset.Pair, version uint64, trader sdk.AccAddress) action.Action {
return settlePositionShouldFail{pair: pair, version: version, trader: trader}
}
29 changes: 27 additions & 2 deletions x/perp/v2/integration/assertion/position.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,45 @@ func Position_PositionShouldBeEqualTo(expectedPosition types.Position) PositionC
type positionShouldNotExist struct {
Account sdk.AccAddress
Pair asset.Pair
Version uint64
}

func (p positionShouldNotExist) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, error, bool) {
_, err := app.PerpKeeperV2.GetPosition(ctx, p.Pair, 1, p.Account)
_, err := app.PerpKeeperV2.GetPosition(ctx, p.Pair, p.Version, p.Account)
if err == nil {
return ctx, fmt.Errorf("position should not exist, but it does with pair %s", p.Pair), false
}

return ctx, nil, false
}

func PositionShouldNotExist(account sdk.AccAddress, pair asset.Pair) action.Action {
func PositionShouldNotExist(account sdk.AccAddress, pair asset.Pair, version uint64) action.Action {
return positionShouldNotExist{
Account: account,
Pair: pair,
Version: version,
}
}

type positionShouldExist struct {
Account sdk.AccAddress
Pair asset.Pair
Version uint64
}

func (p positionShouldExist) Do(app *app.NibiruApp, ctx sdk.Context) (sdk.Context, error, bool) {
_, err := app.PerpKeeperV2.GetPosition(ctx, p.Pair, p.Version, p.Account)
if err != nil {
return ctx, fmt.Errorf("position should exist, but it does not with pair %s", p.Pair), false
}

return ctx, nil, false
}

func PositionShouldExist(account sdk.AccAddress, pair asset.Pair, version uint64) action.Action {
return positionShouldExist{
Account: account,
Pair: pair,
Version: version,
}
}
Loading

0 comments on commit 4561f47

Please sign in to comment.