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

Feat/perp close estimation #828

Merged
merged 7 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,431 changes: 855 additions & 576 deletions docs/static/openapi.yml

Large diffs are not rendered by default.

32 changes: 25 additions & 7 deletions proto/elys/perpetual/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,15 @@ service Query {
option (google.api.http).get = "/elys-network/elys/perpetual/get_all_to_pay";

}

// Queries a list of CloseEstimation items.
rpc CloseEstimation (QueryCloseEstimationRequest) returns (QueryCloseEstimationResponse) {
option (google.api.http).get = "/elys-network/elys/perpetual/close-estimation/{position_id}";

}
}

message MtpAndPrice {
MTP mtp =1;
MTP mtp = 1;
string trading_asset_price = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
Expand All @@ -99,6 +104,7 @@ message MtpAndPrice {
(gogoproto.nullable) = false
];
}

// ParamsRequest is request type for the Query/Params RPC method.
message ParamsRequest {}

Expand All @@ -114,7 +120,7 @@ message PositionsRequest {
}

message PositionsResponse {
repeated MtpAndPrice mtps = 1;
repeated MtpAndPrice mtps = 1;
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

Expand All @@ -124,7 +130,7 @@ message PositionsByPoolRequest {
}

message PositionsByPoolResponse {
repeated MtpAndPrice mtps = 1;
repeated MtpAndPrice mtps = 1;
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

Expand All @@ -141,7 +147,7 @@ message PositionsForAddressRequest {
}

message PositionsForAddressResponse {
repeated MtpAndPrice mtps = 1;
repeated MtpAndPrice mtps = 1;
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

Expand Down Expand Up @@ -176,8 +182,8 @@ message QueryAllPoolRequest {
}

message QueryAllPoolResponse {
repeated PoolResponse pool = 1 [(gogoproto.nullable) = false];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
repeated PoolResponse pool = 1 [(gogoproto.nullable) = false];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

message MTPRequest {
Expand Down Expand Up @@ -252,6 +258,18 @@ message PoolResponse {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
}

message QueryCloseEstimationRequest {
string address = 1;
uint64 position_id = 2;
}

message QueryCloseEstimationResponse {
Position position = 1;
cosmos.base.v1beta1.Coin position_size = 2 [(gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin liabilities = 3 [(gogoproto.nullable) = false];
string price_impact = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string swap_fee = 5 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin return_amount = 6 [(gogoproto.nullable) = false];
}
4 changes: 2 additions & 2 deletions testutil/keeper/perpetual.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"github.com/stretchr/testify/require"
)

func PerpetualKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
func PerpetualKeeper(t testing.TB) (*keeper.Keeper, sdk.Context, *mocks.AssetProfileKeeper) {
storeKey := sdk.NewKVStoreKey(types.StoreKey)
memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey)

Expand Down Expand Up @@ -52,5 +52,5 @@ func PerpetualKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
params := types.DefaultParams()
k.SetParams(ctx, &params)

return k, ctx
return k, ctx, assetProfileKeeper
}
4 changes: 2 additions & 2 deletions x/amm/types/calc_in_amt_given_out.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ func (p Pool) CalcInAmtGivenOut(
}

amountInWithoutSlippage := sdk.NewDecFromInt(tokenOut.Amount).Quo(rate)
if tokenAmountIn.IsZero(){
if tokenAmountIn.IsZero() {
return sdk.Coin{}, sdk.ZeroDec(), ErrAmountTooLow
}
}
slippage = sdk.OneDec().Sub(amountInWithoutSlippage.Quo(tokenAmountIn))

// Ensure (1 - swapfee) is not zero to avoid division by zero
Expand Down
6 changes: 3 additions & 3 deletions x/amm/types/calc_out_amt_given_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ func (p Pool) CalcOutAmtGivenIn(
if err != nil {
return sdk.Coin{}, sdk.ZeroDec(), err
}
if tokenAmountOut.IsZero(){
if tokenAmountOut.IsZero() {
return sdk.Coin{}, sdk.ZeroDec(), ErrAmountTooLow
}
}

rate, err := p.GetTokenARate(ctx, oracle, snapshot, tokenIn.Denom, tokenOutDenom, accountedPool)
if err != nil {
Expand All @@ -80,7 +80,7 @@ func (p Pool) CalcOutAmtGivenIn(
if amountOutWithoutSlippage.IsZero() {
return sdk.Coin{}, sdk.ZeroDec(), errorsmod.Wrapf(ErrInvalidMathApprox, "amount out without slippage must be positive")
}

slippage := sdk.OneDec().Sub(tokenAmountOut.Quo(amountOutWithoutSlippage))

// We ignore the decimal component, as we round down the token amount out.
Expand Down
2 changes: 2 additions & 0 deletions x/perpetual/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@

cmd.AddCommand(CmdGetAllToPay())

cmd.AddCommand(CmdCloseEstimation())

Check warning on line 41 in x/perpetual/client/cli/query.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/query.go#L41

Added line #L41 was not covered by tests

// this line is used by starport scaffolding # 1

return cmd
Expand Down
52 changes: 52 additions & 0 deletions x/perpetual/client/cli/query_close_estimation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package cli

import (
"strconv"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/elys-network/elys/x/perpetual/types"
"github.com/spf13/cast"
"github.com/spf13/cobra"
)

var _ = strconv.Itoa(0)

func CmdCloseEstimation() *cobra.Command {
cmd := &cobra.Command{
Use: "close-estimation [address] [position-id]",
Short: "Query close-estimation",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) (err error) {
reqAddress := args[0]

Check warning on line 21 in x/perpetual/client/cli/query_close_estimation.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/query_close_estimation.go#L15-L21

Added lines #L15 - L21 were not covered by tests

reqPositionId, err := cast.ToUint64E(args[1])
if err != nil {
return err

Check warning on line 25 in x/perpetual/client/cli/query_close_estimation.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/query_close_estimation.go#L23-L25

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

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

Check warning on line 30 in x/perpetual/client/cli/query_close_estimation.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/query_close_estimation.go#L28-L30

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

queryClient := types.NewQueryClient(clientCtx)

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

View check run for this annotation

Codecov / codecov/patch

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

Added line #L33 was not covered by tests

params := &types.QueryCloseEstimationRequest{
Address: reqAddress,
PositionId: reqPositionId,

Check warning on line 37 in x/perpetual/client/cli/query_close_estimation.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/query_close_estimation.go#L35-L37

Added lines #L35 - L37 were not covered by tests
}

res, err := queryClient.CloseEstimation(cmd.Context(), params)
if err != nil {
return err

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

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/query_close_estimation.go#L40-L42

Added lines #L40 - L42 were not covered by tests
}

return clientCtx.PrintProto(res)

Check warning on line 45 in x/perpetual/client/cli/query_close_estimation.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/query_close_estimation.go#L45

Added line #L45 was not covered by tests
},
}

flags.AddQueryFlagsToCmd(cmd)

Check warning on line 49 in x/perpetual/client/cli/query_close_estimation.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/query_close_estimation.go#L49

Added line #L49 was not covered by tests

return cmd

Check warning on line 51 in x/perpetual/client/cli/query_close_estimation.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/client/cli/query_close_estimation.go#L51

Added line #L51 was not covered by tests
}
2 changes: 1 addition & 1 deletion x/perpetual/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestGenesis(t *testing.T) {
// this line is used by starport scaffolding # genesis/test/state
}

k, ctx := keepertest.PerpetualKeeper(t)
k, ctx, _ := keepertest.PerpetualKeeper(t)
perpetual.InitGenesis(ctx, *k, genesisState)
got := perpetual.ExportGenesis(ctx, *k)
require.NotNil(t, got)
Expand Down
2 changes: 1 addition & 1 deletion x/perpetual/keeper/borrow_rate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func createNBorrowRate(keeper *keeper.Keeper, ctx sdk.Context, n int) ([]types.I
}

func TestBorrowRateGet(t *testing.T) {
keeper, ctx := keepertest.PerpetualKeeper(t)
keeper, ctx, _ := keepertest.PerpetualKeeper(t)
_, lastBlock := createNBorrowRate(keeper, ctx, 10)
ctx = ctx.WithBlockHeight(lastBlock)

Expand Down
75 changes: 75 additions & 0 deletions x/perpetual/keeper/calc_return_amount.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package keeper

import (
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
ammtypes "github.com/elys-network/elys/x/amm/types"
"github.com/elys-network/elys/x/perpetual/types"
)

func (k Keeper) CalcReturnAmount(ctx sdk.Context, mtp types.MTP, pool types.Pool, ammPool ammtypes.Pool, repayAmount math.Int, amount math.Int, baseCurrency string) (returnAmount math.Int, err error) {
Liabilities := mtp.Liabilities
BorrowInterestUnpaid := mtp.BorrowInterestUnpaidCollateral

if mtp.BorrowInterestUnpaidCollateral.IsPositive() {
if mtp.Position == types.Position_SHORT {
// swap to trading asset
unpaidCollateralIn := sdk.NewCoin(mtp.CollateralAsset, mtp.BorrowInterestUnpaidCollateral)
C, err := k.CloseEstimationChecker.EstimateSwapGivenOut(ctx, unpaidCollateralIn, mtp.TradingAsset, ammPool)
if err != nil {
return sdk.ZeroInt(), err

Check warning on line 20 in x/perpetual/keeper/calc_return_amount.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/calc_return_amount.go#L17-L20

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

BorrowInterestUnpaid = C

Check warning on line 23 in x/perpetual/keeper/calc_return_amount.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/calc_return_amount.go#L23

Added line #L23 was not covered by tests
} else if mtp.CollateralAsset != baseCurrency {
// swap to base currency
unpaidCollateralIn := sdk.NewCoin(mtp.CollateralAsset, mtp.BorrowInterestUnpaidCollateral)
C, err := k.CloseEstimationChecker.EstimateSwapGivenOut(ctx, unpaidCollateralIn, baseCurrency, ammPool)
if err != nil {
return sdk.ZeroInt(), err

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

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/calc_return_amount.go#L29

Added line #L29 was not covered by tests
}

BorrowInterestUnpaid = C
}
}

// Reminder:
// if long both repay amount and liablities are collateral asset
// if short both repay amount and liablities are trading asset

have := repayAmount
owe := Liabilities.Add(BorrowInterestUnpaid).Mul(amount.Quo(mtp.Custody))

if have.LT(owe) {
// v principle liability; x excess liability
returnAmount = sdk.ZeroInt()
} else {
// can afford both
returnAmount = have.Sub(owe)
}

// returnAmount is so far in base currency if long or trading asset if short, now should convert it to collateralAsset in order to return
if returnAmount.IsPositive() {
if mtp.Position == types.Position_SHORT {
// swap to collateral asset
amtTokenIn := sdk.NewCoin(mtp.TradingAsset, returnAmount)
C, err := k.CloseEstimationChecker.EstimateSwapGivenOut(ctx, amtTokenIn, mtp.CollateralAsset, ammPool)
if err != nil {
return sdk.ZeroInt(), err

Check warning on line 58 in x/perpetual/keeper/calc_return_amount.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/calc_return_amount.go#L55-L58

Added lines #L55 - L58 were not covered by tests
}

returnAmount = C

Check warning on line 61 in x/perpetual/keeper/calc_return_amount.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/calc_return_amount.go#L61

Added line #L61 was not covered by tests
} else if mtp.CollateralAsset != baseCurrency {
// swap to collateral asset
amtTokenIn := sdk.NewCoin(baseCurrency, returnAmount)
C, err := k.CloseEstimationChecker.EstimateSwapGivenOut(ctx, amtTokenIn, mtp.CollateralAsset, ammPool)
if err != nil {
return sdk.ZeroInt(), err

Check warning on line 67 in x/perpetual/keeper/calc_return_amount.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/calc_return_amount.go#L67

Added line #L67 was not covered by tests
}

returnAmount = C
}
}

return returnAmount, nil
}
18 changes: 17 additions & 1 deletion x/perpetual/keeper/estimate_and_repay.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,24 @@
return sdk.ZeroInt(), types.ErrInvalidPosition
}

returnAmount, err := k.CalcReturnAmount(ctx, mtp, pool, ammPool, repayAmount, amount, baseCurrency)
if err != nil {
return sdk.ZeroInt(), err

Check warning on line 35 in x/perpetual/keeper/estimate_and_repay.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/estimate_and_repay.go#L35

Added line #L35 was not covered by tests
}

// update mtp health
mtp.MtpHealth, err = k.GetMTPHealth(ctx, mtp, ammPool, baseCurrency)
if err != nil {
return sdk.ZeroInt(), err

Check warning on line 41 in x/perpetual/keeper/estimate_and_repay.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/estimate_and_repay.go#L41

Added line #L41 was not covered by tests
}

// if return amount positive then update liabilities
if returnAmount.IsPositive() {
mtp.Liabilities = mtp.Liabilities.Sub(mtp.Liabilities.Mul(amount).Quo(mtp.Custody))
}

// Note: Long settlement is done in trading asset. And short settlement in usdc in Repay function
if err := k.Repay(ctx, &mtp, &pool, ammPool, repayAmount, false, amount, baseCurrency); err != nil {
if err := k.Repay(ctx, &mtp, &pool, ammPool, returnAmount, amount); err != nil {
return sdk.ZeroInt(), err
}

Expand Down
10 changes: 10 additions & 0 deletions x/perpetual/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
types.OpenShortChecker
types.CloseLongChecker
types.CloseShortChecker
types.CloseEstimationChecker

cdc codec.BinaryCodec
storeKey storetypes.StoreKey
Expand Down Expand Up @@ -76,6 +77,7 @@
keeper.OpenShortChecker = keeper
keeper.CloseLongChecker = keeper
keeper.CloseShortChecker = keeper
keeper.CloseEstimationChecker = keeper

return keeper
}
Expand Down Expand Up @@ -457,6 +459,14 @@
return takeAmount, nil
}

// CalcTakeFundPayment calculates the take fund payment
func (k Keeper) CalcTakeFundPayment(ctx sdk.Context, returnAmount math.Int, returnAsset string, takePercentage sdk.Dec) math.Int {
returnAmountDec := sdk.NewDecFromBigInt(returnAmount.BigInt())
takeAmount := sdk.NewIntFromBigInt(takePercentage.Mul(returnAmountDec).TruncateInt().BigInt())

Check warning on line 465 in x/perpetual/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/keeper.go#L463-L465

Added lines #L463 - L465 were not covered by tests

return takeAmount

Check warning on line 467 in x/perpetual/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/perpetual/keeper/keeper.go#L467

Added line #L467 was not covered by tests
}

// Set the perpetual hooks.
func (k *Keeper) SetHooks(gh types.PerpetualHooks) *Keeper {
if k.hooks != nil {
Expand Down
2 changes: 1 addition & 1 deletion x/perpetual/keeper/msg_server_update_take_profit_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import (

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

func (k msgServer) UpdateTakeProfitPrice(goCtx context.Context, msg *types.MsgUpdateTakeProfitPrice) (*types.MsgUpdateTakeProfitPriceResponse, error) {
Expand Down
2 changes: 1 addition & 1 deletion x/perpetual/keeper/msg_servers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ import (
)

func setupMsgServer(t testing.TB) (types.MsgServer, context.Context) {
k, ctx := keepertest.PerpetualKeeper(t)
k, ctx, _ := keepertest.PerpetualKeeper(t)
return keeper.NewMsgServerImpl(*k), sdk.WrapSDKContext(ctx)
}
2 changes: 1 addition & 1 deletion x/perpetual/keeper/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestGetParams(t *testing.T) {
k, ctx := testkeeper.PerpetualKeeper(t)
k, ctx, _ := testkeeper.PerpetualKeeper(t)
params := types.DefaultParams()

k.SetParams(ctx, &params)
Expand Down
Loading
Loading