Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Perpetual]: add stop loss price #759

Merged
merged 14 commits into from
Sep 10, 2024
19 changes: 18 additions & 1 deletion proto/elys/perpetual/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ service Msg {
rpc Whitelist (MsgWhitelist ) returns (MsgWhitelistResponse );
rpc Dewhitelist (MsgDewhitelist ) returns (MsgDewhitelistResponse );
rpc AddCollateral (MsgAddCollateral ) returns (MsgAddCollateralResponse );
rpc BrokerAddCollateral (MsgBrokerAddCollateral) returns (MsgAddCollateralResponse);
rpc BrokerAddCollateral (MsgBrokerAddCollateral) returns (MsgAddCollateralResponse );
rpc UpdateStopLoss (MsgUpdateStopLoss ) returns (MsgUpdateStopLossResponse );
}
message MsgOpen {
string creator = 1;
Expand All @@ -28,6 +29,10 @@ message MsgOpen {
string trading_asset = 4;
cosmos.base.v1beta1.Coin collateral = 5 [(gogoproto.nullable) = false ] ;
string take_profit_price = 6 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string stop_loss_price = 28 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

message MsgBrokerOpen {
Expand All @@ -38,6 +43,10 @@ message MsgBrokerOpen {
cosmos.base.v1beta1.Coin collateral = 5 [(gogoproto.nullable) = false ] ;
string take_profit_price = 6 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string owner = 7;
string stop_loss_price = 28 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

message MsgOpenResponse {
Expand Down Expand Up @@ -101,3 +110,11 @@ message MsgBrokerAddCollateral {
int32 id = 3;
string owner = 4;
}

message MsgUpdateStopLoss {
string creator = 1;
uint64 id = 2;
string price = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}

message MsgUpdateStopLossResponse {}
93 changes: 93 additions & 0 deletions proto/elys/perpetual/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,99 @@ message MTP {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
string stop_loss_price = 28 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

message LegacyMTP {
string address = 1;
string collateral_asset = 2;
string trading_asset = 3;
string liabilities_asset = 4;
string custody_asset = 5;
string collateral = 6 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string liabilities = 7 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string borrow_interest_paid_collateral = 8 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string borrow_interest_paid_custody = 9 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string borrow_interest_unpaid_collateral = 10 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string custody = 11 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string take_profit_liabilities = 12 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string take_profit_custody = 13 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string leverage = 14 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
string mtp_health = 15 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
Position position = 16;
uint64 id = 17;
uint64 amm_pool_id = 18;
string consolidate_leverage = 19 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
string sum_collateral = 20 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string take_profit_price = 21 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
string take_profit_borrow_rate = 22 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// funding fee paid
string funding_fee_paid_collateral = 23 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string funding_fee_paid_custody = 24 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
// funding fee received
string funding_fee_received_collateral = 25 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string funding_fee_received_custody = 26 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string open_price = 27 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

message WhiteList {
Expand Down
1 change: 1 addition & 0 deletions x/perpetual/client/cli/query_mtp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func networkWithMTPObjects(t *testing.T, n int) (*network.Network, []*types.MTP)
FundingFeeReceivedCollateral: sdk.NewInt(0),
FundingFeeReceivedCustody: sdk.NewInt(0),
OpenPrice: sdk.NewDec(0),
StopLossPrice: sdk.NewDec(0),
}

mtps = append(mtps, &mtp)
Expand Down
1 change: 1 addition & 0 deletions x/perpetual/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
cmd.AddCommand(CmdWhitelist())
cmd.AddCommand(CmdDewhitelist())
cmd.AddCommand(CmdAddCollateral())
cmd.AddCommand(CmdUpdateStopLoss())

Check warning on line 33 in x/perpetual/client/cli/tx.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/tx.go#L33

Added line #L33 was not covered by tests
// this line is used by starport scaffolding # 1

return cmd
Expand Down
14 changes: 10 additions & 4 deletions x/perpetual/client/cli/tx_open.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@

func CmdOpen() *cobra.Command {
cmd := &cobra.Command{
Use: "open [position] [leverage] [trading-asset] [collateral] [flags]",
Use: "open [position] [leverage] [trading-asset] [collateral] [stop-loss-price] [flags]",
Short: "Open perpetual position",
Example: `Infinte profitability:
elysd tx perpetual open long 5 uatom 100000000uusdc --from=treasury --keyring-backend=test --chain-id=elystestnet-1 --yes --gas=1000000
elysd tx perpetual open long 5 uatom 100000000uusdc 100.0 --from=treasury --keyring-backend=test --chain-id=elystestnet-1 --yes --gas=1000000
Finite profitability:
elysd tx perpetual open short 5 uatom 100000000uusdc --take-profit 100 --from=treasury --keyring-backend=test --chain-id=elystestnet-1 --yes --gas=1000000`,
Args: cobra.ExactArgs(4),
elysd tx perpetual open short 5 uatom 100000000uusdc 100.0 --take-profit 100 --from=treasury --keyring-backend=test --chain-id=elystestnet-1 --yes --gas=1000000`,
Args: cobra.ExactArgs(5),
RunE: func(cmd *cobra.Command, args []string) (err error) {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
Expand Down Expand Up @@ -50,6 +50,11 @@
return err
}

stopLossPrice, err := sdk.NewDecFromStr(args[4])
if err != nil {
return err

Check warning on line 55 in x/perpetual/client/cli/tx_open.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/tx_open.go#L55

Added line #L55 was not covered by tests
}

var takeProfitPrice sdk.Dec
if takeProfitPriceStr != types.InfinitePriceString {
takeProfitPrice, err = sdk.NewDecFromStr(takeProfitPriceStr)
Expand All @@ -70,6 +75,7 @@
argTradingAsset,
argCollateral,
takeProfitPrice,
stopLossPrice,
)

if err := msg.ValidateBasic(); err != nil {
Expand Down
1 change: 1 addition & 0 deletions x/perpetual/client/cli/tx_open_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func TestOpenPosition(t *testing.T) {
"1.5",
"uatom",
"1000" + ptypes.BaseCurrency,
"100.0",
"--from=" + val.Address.String(),
"-y",
}
Expand Down
51 changes: 51 additions & 0 deletions x/perpetual/client/cli/tx_update_stop_loss.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package cli

import (
"errors"
"strconv"

"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/elys-network/elys/x/perpetual/types"
"github.com/spf13/cobra"
)

func CmdUpdateStopLoss() *cobra.Command {
cmd := &cobra.Command{
Use: "update-stop-loss [id] [amount]",
Short: "Broadcast message update-stop-loss",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) (err error) {
argPrice, err := sdk.NewDecFromStr(args[0])
if err!=nil {
return errors.New("invalid stoploss amount")

Check warning on line 24 in x/perpetual/client/cli/tx_update_stop_loss.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/tx_update_stop_loss.go#L24

Added line #L24 was not covered by tests
}
positionId, err := strconv.Atoi(args[1])
if err != nil {
return err

Check warning on line 28 in x/perpetual/client/cli/tx_update_stop_loss.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/tx_update_stop_loss.go#L28

Added line #L28 was not covered by tests
}

clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err

Check warning on line 33 in x/perpetual/client/cli/tx_update_stop_loss.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/tx_update_stop_loss.go#L33

Added line #L33 was not covered by tests
}

msg := types.NewMsgUpdateStopLoss(
clientCtx.GetFromAddress().String(),
uint64(positionId),
math.LegacyDec(argPrice),
)
if err := msg.ValidateBasic(); err != nil {
return err

Check warning on line 42 in x/perpetual/client/cli/tx_update_stop_loss.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/tx_update_stop_loss.go#L42

Added line #L42 was not covered by tests
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}
30 changes: 30 additions & 0 deletions x/perpetual/client/cli/tx_update_stop_loss_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package cli_test

import (
"testing"

clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/stretchr/testify/require"

"github.com/elys-network/elys/x/perpetual/client/cli"
)

func TestUpdatestopLoss(t *testing.T) {
net := setupNetwork(t)
ctx := net.Validators[0].ClientCtx
val := net.Validators[0]

// Use baseURL to make API HTTP requests or use val.RPCClient to make direct
// Tendermint RPC calls.
// ...

args := []string{
"100.0",
"1",
"--from=" + val.Address.String(),
"-y",
}

_, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdUpdateStopLoss(), args)
require.NoError(t, err)
}
1 change: 1 addition & 0 deletions x/perpetual/keeper/check_same_asset_position_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func TestCheckSameAssetPosition_NewPosition(t *testing.T) {
Leverage: sdk.NewDec(1),
TradingAsset: ptypes.ATOM,
Collateral: sdk.NewCoin(ptypes.ATOM, sdk.NewInt(100)),
StopLossPrice: sdk.NewDec(100),
}

mtp = k.CheckSameAssetPosition(ctx, msg)
Expand Down
1 change: 1 addition & 0 deletions x/perpetual/keeper/invariant_check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ func TestCheckBalanceInvariant_InvalidBalance(t *testing.T) {
ptypes.ATOM,
sdk.NewCoin(ptypes.BaseCurrency, sdk.NewInt(100000000)),
sdk.MustNewDecFromStr(perpetualtypes.TakeProfitPriceDefault),
sdk.NewDec(100),
)

_, err = mk.Open(ctx, msg2, false)
Expand Down
2 changes: 1 addition & 1 deletion x/perpetual/keeper/msg_server_broker_open.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
return nil, errors.Wrap(types.ErrUnauthorised, "creator must be broker address")
}

msgOpen := types.NewMsgOpen(msg.Owner, msg.Position, msg.Leverage, msg.TradingAsset, msg.Collateral, msg.TakeProfitPrice)
msgOpen := types.NewMsgOpen(msg.Owner, msg.Position, msg.Leverage, msg.TradingAsset, msg.Collateral, msg.TakeProfitPrice, msg.StopLossPrice)

Check warning on line 24 in x/perpetual/keeper/msg_server_broker_open.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/msg_server_broker_open.go#L24

Added line #L24 was not covered by tests

return k.Keeper.Open(ctx, msgOpen, true)
}
43 changes: 43 additions & 0 deletions x/perpetual/keeper/msg_server_update_stop_loss.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package keeper

import (
"context"
"fmt"
"strconv"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/elys-network/elys/x/perpetual/types"
)

func (k msgServer) UpdateStopLoss(goCtx context.Context, msg *types.MsgUpdateStopLoss) (*types.MsgUpdateStopLossResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

Check warning on line 14 in x/perpetual/keeper/msg_server_update_stop_loss.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/msg_server_update_stop_loss.go#L13-L14

Added lines #L13 - L14 were not covered by tests

// Load existing mtp
mtp, err := k.GetMTP(ctx, msg.Creator, msg.Id)
if err != nil {
return nil, err

Check warning on line 19 in x/perpetual/keeper/msg_server_update_stop_loss.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/msg_server_update_stop_loss.go#L17-L19

Added lines #L17 - L19 were not covered by tests
}

poolId := mtp.AmmPoolId
pool, found := k.GetPool(ctx, poolId)
if !found {
return nil, errorsmod.Wrap(types.ErrPoolDoesNotExist, fmt.Sprintf("poolId: %d", poolId))

Check warning on line 25 in x/perpetual/keeper/msg_server_update_stop_loss.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/msg_server_update_stop_loss.go#L22-L25

Added lines #L22 - L25 were not covered by tests
}

if !pool.Enabled {
return nil, errorsmod.Wrap(types.ErrPerpetualDisabled, fmt.Sprintf("poolId: %d", poolId))

Check warning on line 29 in x/perpetual/keeper/msg_server_update_stop_loss.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/msg_server_update_stop_loss.go#L28-L29

Added lines #L28 - L29 were not covered by tests
}

mtp.StopLossPrice = msg.Price
k.SetMTP(ctx, &mtp)

Check warning on line 33 in x/perpetual/keeper/msg_server_update_stop_loss.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/msg_server_update_stop_loss.go#L32-L33

Added lines #L32 - L33 were not covered by tests

event := sdk.NewEvent(types.EventOpen,
sdk.NewAttribute("id", strconv.FormatInt(int64(mtp.Id), 10)),
sdk.NewAttribute("address", mtp.Address),
sdk.NewAttribute("stop_loss", mtp.StopLossPrice.String()),
)
ctx.EventManager().EmitEvent(event)

Check warning on line 40 in x/perpetual/keeper/msg_server_update_stop_loss.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/msg_server_update_stop_loss.go#L35-L40

Added lines #L35 - L40 were not covered by tests

return &types.MsgUpdateStopLossResponse{}, nil

Check warning on line 42 in x/perpetual/keeper/msg_server_update_stop_loss.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/msg_server_update_stop_loss.go#L42

Added line #L42 was not covered by tests
}
33 changes: 33 additions & 0 deletions x/perpetual/keeper/mtp.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,36 @@
}
return count
}


func (k Keeper) DeleteLegacyMTP(ctx sdk.Context, mtpaddress string, id uint64) error {
store := ctx.KVStore(k.storeKey)
key := types.GetMTPKey(mtpaddress, id)
if !store.Has(key) {
return types.ErrMTPDoesNotExist

Check warning on line 206 in x/perpetual/keeper/mtp.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/mtp.go#L202-L206

Added lines #L202 - L206 were not covered by tests
}
store.Delete(key)
return nil

Check warning on line 209 in x/perpetual/keeper/mtp.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/mtp.go#L208-L209

Added lines #L208 - L209 were not covered by tests
}

func (k Keeper) GetAllLegacyMTP(ctx sdk.Context) []types.LegacyMTP {
var mtps []types.LegacyMTP
iterator := k.GetMTPIterator(ctx)
defer func(iterator sdk.Iterator) {
err := iterator.Close()
if err != nil {
panic(err)

Check warning on line 218 in x/perpetual/keeper/mtp.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/mtp.go#L212-L218

Added lines #L212 - L218 were not covered by tests
}
}(iterator)

for ; iterator.Valid(); iterator.Next() {
var mtp types.LegacyMTP
bytesValue := iterator.Value()
err := k.cdc.Unmarshal(bytesValue, &mtp)
if err == nil {
mtps = append(mtps, mtp)

Check warning on line 227 in x/perpetual/keeper/mtp.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/mtp.go#L222-L227

Added lines #L222 - L227 were not covered by tests
}
}

return mtps

Check warning on line 231 in x/perpetual/keeper/mtp.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/mtp.go#L231

Added line #L231 was not covered by tests
}
Loading
Loading