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

refactor: margin functions #194

Merged
merged 4 commits into from
Sep 18, 2023
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
19 changes: 18 additions & 1 deletion x/amm/types/query.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion x/margin/keeper/check_long_assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
ptypes "github.com/elys-network/elys/x/parameter/types"
)

func (k Keeper) CheckLongingAssets(ctx sdk.Context, collateralAsset string, borrowAsset string) error {
func (k Keeper) CheckLongAssets(ctx sdk.Context, collateralAsset string, borrowAsset string) error {
if borrowAsset == ptypes.BaseCurrency {
return sdkerrors.Wrap(types.ErrInvalidBorrowingAsset, "invalid borrowing asset")
}
Expand Down
8 changes: 4 additions & 4 deletions x/margin/keeper/check_long_assets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ func TestCheckLongAssets_InvalidAssets(t *testing.T) {

ctx := sdk.Context{} // mock or setup a context

err := k.CheckLongingAssets(ctx, ptypes.BaseCurrency, ptypes.BaseCurrency)
err := k.CheckLongAssets(ctx, ptypes.BaseCurrency, ptypes.BaseCurrency)
assert.True(t, errors.Is(err, sdkerrors.Wrap(types.ErrInvalidBorrowingAsset, "invalid borrowing asset")))

err = k.CheckLongingAssets(ctx, ptypes.ATOM, ptypes.BaseCurrency)
err = k.CheckLongAssets(ctx, ptypes.ATOM, ptypes.BaseCurrency)
assert.True(t, errors.Is(err, sdkerrors.Wrap(types.ErrInvalidBorrowingAsset, "invalid borrowing asset")))

// Expect no error
Expand All @@ -46,10 +46,10 @@ func TestCheckLongAssets_ValidAssets(t *testing.T) {

ctx := sdk.Context{} // mock or setup a context

err := k.CheckLongingAssets(ctx, ptypes.BaseCurrency, ptypes.ATOM)
err := k.CheckLongAssets(ctx, ptypes.BaseCurrency, ptypes.ATOM)
assert.Nil(t, err)

err = k.CheckLongingAssets(ctx, ptypes.ATOM, ptypes.ATOM)
err = k.CheckLongAssets(ctx, ptypes.ATOM, ptypes.ATOM)
assert.Nil(t, err)

// Expect an error about max open positions
Expand Down
27 changes: 27 additions & 0 deletions x/margin/keeper/check_short_assets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/elys-network/elys/x/margin/types"
ptypes "github.com/elys-network/elys/x/parameter/types"
)

func (k Keeper) CheckShortAssets(ctx sdk.Context, collateralAsset string, borrowAsset string) error {
// You shouldn't be shorting the base currency (like USDC).
if borrowAsset == ptypes.BaseCurrency {
return sdkerrors.Wrap(types.ErrInvalidBorrowingAsset, "cannot short the base currency")
}

// If both the collateralAsset and borrowAsset are the same, it doesn't make sense.
if collateralAsset == borrowAsset {
return sdkerrors.Wrap(types.ErrInvalidCollateralAsset, "collateral asset cannot be the same as the borrowed asset in a short position")
}

// The collateral for a short must be the base currency.
if collateralAsset != ptypes.BaseCurrency {
return sdkerrors.Wrap(types.ErrInvalidCollateralAsset, "collateral asset for a short position must be the base currency")
}

return nil
}
59 changes: 59 additions & 0 deletions x/margin/keeper/check_short_assets_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package keeper_test

import (
"errors"
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/elys-network/elys/x/margin/keeper"
"github.com/elys-network/elys/x/margin/types"
"github.com/elys-network/elys/x/margin/types/mocks"
"github.com/stretchr/testify/assert"

ptypes "github.com/elys-network/elys/x/parameter/types"
)

func TestCheckShortAssets_InvalidAssets(t *testing.T) {
// Setup the mock checker
mockChecker := new(mocks.OpenShortChecker)

// Create an instance of Keeper with the mock checker
k := keeper.Keeper{
OpenShortChecker: mockChecker,
}

ctx := sdk.Context{} // mock or setup a context

// Test invalid cases for short positions
err := k.CheckShortAssets(ctx, ptypes.ATOM, ptypes.BaseCurrency)
assert.True(t, errors.Is(err, sdkerrors.Wrap(types.ErrInvalidBorrowingAsset, "cannot short the base currency")))

err = k.CheckShortAssets(ctx, ptypes.ATOM, ptypes.ATOM)
assert.True(t, errors.Is(err, sdkerrors.Wrap(types.ErrInvalidCollateralAsset, "collateral asset cannot be the same as the borrowed asset in a short position")))

err = k.CheckShortAssets(ctx, ptypes.ATOM, "btc")
assert.True(t, errors.Is(err, sdkerrors.Wrap(types.ErrInvalidCollateralAsset, "collateral asset for a short position must be the base currency")))

// Expect no error
mockChecker.AssertExpectations(t)
}

func TestCheckShortAssets_ValidAssets(t *testing.T) {
// Setup the mock checker
mockChecker := new(mocks.OpenShortChecker)

// Create an instance of Keeper with the mock checker
k := keeper.Keeper{
OpenShortChecker: mockChecker,
}

ctx := sdk.Context{} // mock or setup a context

// Test valid case for short position
err := k.CheckShortAssets(ctx, ptypes.BaseCurrency, ptypes.ATOM)
assert.Nil(t, err)

// Expect no error
mockChecker.AssertExpectations(t)
}
14 changes: 12 additions & 2 deletions x/margin/keeper/open.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,18 @@ import (
)

func (k Keeper) Open(ctx sdk.Context, msg *types.MsgOpen) (*types.MsgOpenResponse, error) {
if err := k.OpenChecker.CheckLongingAssets(ctx, msg.CollateralAsset, msg.BorrowAsset); err != nil {
return nil, err
// Determine the type of position (long or short) and validate assets accordingly.
switch msg.Position {
case types.Position_LONG:
if err := k.OpenChecker.CheckLongAssets(ctx, msg.CollateralAsset, msg.BorrowAsset); err != nil {
return nil, err
}
case types.Position_SHORT:
if err := k.OpenChecker.CheckShortAssets(ctx, msg.CollateralAsset, msg.BorrowAsset); err != nil {
return nil, err
}
default:
return nil, sdkerrors.Wrap(types.ErrInvalidPosition, msg.Position.String())
}

if err := k.OpenChecker.CheckUserAuthorization(ctx, msg); err != nil {
Expand Down
17 changes: 16 additions & 1 deletion x/margin/keeper/open_long_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,29 @@ import (
)

func (k Keeper) ProcessOpenLong(ctx sdk.Context, mtp *types.MTP, leverage sdk.Dec, eta sdk.Dec, collateralAmountDec sdk.Dec, poolId uint64, msg *types.MsgOpen) (*types.MTP, error) {
// Get token asset other than base currency
// Determine the trading asset.
tradingAsset := k.OpenLongChecker.GetTradingAsset(msg.CollateralAsset, msg.BorrowAsset)

// Fetch the pool associated with the given pool ID.
pool, found := k.OpenLongChecker.GetPool(ctx, poolId)
if !found {
return nil, sdkerrors.Wrap(types.ErrPoolDoesNotExist, tradingAsset)
}

// Check if the pool is enabled.
if !k.OpenLongChecker.IsPoolEnabled(ctx, poolId) {
return nil, sdkerrors.Wrap(types.ErrMTPDisabled, tradingAsset)
}

// Fetch the corresponding AMM (Automated Market Maker) pool.
ammPool, err := k.OpenLongChecker.GetAmmPool(ctx, poolId, tradingAsset)
if err != nil {
return nil, err
}

// Calculate the leveraged amount based on the collateral provided and the leverage.
leveragedAmount := sdk.NewInt(collateralAmountDec.Mul(leverage).TruncateInt().Int64())

// If collateral is not base currency, calculate the borrowing amount in base currency and check the balance
if msg.CollateralAsset != ptypes.BaseCurrency {
custodyAmtToken := sdk.NewCoin(msg.CollateralAsset, leveragedAmount)
Expand All @@ -42,12 +47,14 @@ func (k Keeper) ProcessOpenLong(ctx sdk.Context, mtp *types.MTP, leverage sdk.De
}
}

// Check minimum liabilities.
collateralTokenAmt := sdk.NewCoin(msg.CollateralAsset, msg.CollateralAmount)
err = k.OpenLongChecker.CheckMinLiabilities(ctx, collateralTokenAmt, eta, pool, ammPool, msg.BorrowAsset)
if err != nil {
return nil, err
}

// Calculate custody amount.
leveragedAmtTokenIn := sdk.NewCoin(msg.CollateralAsset, leveragedAmount)
custodyAmount, err := k.OpenLongChecker.EstimateSwap(ctx, leveragedAmtTokenIn, msg.BorrowAsset, ammPool)
if err != nil {
Expand All @@ -59,26 +66,34 @@ func (k Keeper) ProcessOpenLong(ctx sdk.Context, mtp *types.MTP, leverage sdk.De
custodyAmount = leveragedAmount
}

// Ensure the AMM pool has enough balance.
if !k.OpenLongChecker.HasSufficientPoolBalance(ctx, ammPool, msg.BorrowAsset, custodyAmount) {
return nil, sdkerrors.Wrap(types.ErrCustodyTooHigh, custodyAmount.String())
}

// Borrow the asset the user wants to long.
err = k.OpenLongChecker.Borrow(ctx, msg.CollateralAsset, msg.BorrowAsset, msg.CollateralAmount, custodyAmount, mtp, &ammPool, &pool, eta)
if err != nil {
return nil, err
}

// Update the pool health.
if err = k.OpenLongChecker.UpdatePoolHealth(ctx, &pool); err != nil {
return nil, err
}

// Take custody from the pool balance.
if err = k.OpenLongChecker.TakeInCustody(ctx, *mtp, &pool); err != nil {
return nil, err
}

// Update the MTP health.
lr, err := k.OpenLongChecker.UpdateMTPHealth(ctx, *mtp, ammPool)
if err != nil {
return nil, err
}

// Check if the MTP is unhealthy
safetyFactor := k.OpenLongChecker.GetSafetyFactor(ctx)
if lr.LTE(safetyFactor) {
return nil, types.ErrMTPUnhealthy
Expand Down
9 changes: 6 additions & 3 deletions x/margin/keeper/open_short_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

func (k Keeper) ProcessOpenShort(ctx sdk.Context, mtp *types.MTP, leverage sdk.Dec, eta sdk.Dec, collateralAmountDec sdk.Dec, poolId uint64, msg *types.MsgOpen) (*types.MTP, error) {
// // Determine the trading asset.
// Determine the trading asset.
// tradingAsset := k.OpenShortChecker.GetTradingAsset(msg.CollateralAsset, msg.BorrowAsset)

// // Fetch the pool associated with the given pool ID.
Expand All @@ -30,9 +30,12 @@ func (k Keeper) ProcessOpenShort(ctx sdk.Context, mtp *types.MTP, leverage sdk.D
// leveragedAmount := sdk.NewInt(collateralAmountDec.Mul(leverage).TruncateInt().Int64())

// // Borrow the asset the user wants to short.
// // ... (Logic to borrow the asset; error handling) ...
// // err = k.OpenLongChecker.Borrow(ctx, msg.CollateralAsset, msg.BorrowAsset, msg.CollateralAmount, custodyAmount, mtp, &ammPool, &pool, eta)
// // if err != nil {
// // return nil, err
// // }

// // Swap the borrowed asset for base currency.
// // Calculate the custody amount.
cosmic-vagabond marked this conversation as resolved.
Show resolved Hide resolved
// swappedAmount, err := k.OpenShortChecker.EstimateSwap(ctx, leveragedAmount, ptypes.BaseCurrency, ammPool)
// if err != nil {
// return nil, err
Expand Down
Loading