Skip to content

Commit

Permalink
feat: add update params message to stablestake (#656)
Browse files Browse the repository at this point in the history
* feat: add update params message to stablestake

* test: fix unit tests
  • Loading branch information
cosmic-vagabond authored Jul 17, 2024
1 parent 8ee5338 commit 2472c14
Show file tree
Hide file tree
Showing 14 changed files with 675 additions and 167 deletions.
1 change: 1 addition & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,7 @@ func NewElysApp(
appCodec,
keys[stablestaketypes.StoreKey],
keys[stablestaketypes.MemStoreKey],
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
app.GetSubspace(stablestaketypes.ModuleName),
app.BankKeeper,
&app.CommitmentKeeper,
Expand Down
45 changes: 0 additions & 45 deletions app/setup_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package app
import (
"fmt"

wasmmodule "github.com/CosmWasm/wasmd/x/wasm"
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
m "github.com/cosmos/cosmos-sdk/types/module"
Expand All @@ -24,49 +22,6 @@ func setUpgradeHandler(app *ElysApp) {
func(ctx sdk.Context, plan upgradetypes.Plan, vm m.VersionMap) (m.VersionMap, error) {
app.Logger().Info("Running upgrade handler for " + version.Version)

if version.Version == "v0.38.2" || version.Version == "v999.999.999" {
// Retrieve the wasm module store key
storeKey := app.keys[wasmmodule.StoreKey]

// Retrieve the wasm module store
store := ctx.KVStore(storeKey)

// List of prefixes to clear
prefixes := [][]byte{
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys1s37xz7tzrru2cpl96juu9lfqrsd4jh73j9slyv440q5vttx2uyesetjpne")), // AH
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys1x8gwn06l85q0lyncy7zsde8zzdn588k2dck00a8j6lkprydcutwqa9tv6n")), // old contract
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys1657pee2jhf4jk8pq6yq64e758ngvum45gl866knmjkd83w6jgn3s923j5j")), // old contract
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys1xhcxq4fvxth2hn3msmkpftkfpw73um7s4et3lh4r8cfmumk3qsmsmgjjrc")), // old contract
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys1wr6vc3g4caz9aclgjacxewr0pjlre9wl2uhq73rp8mawwmqaczsq3ppn83")), // old contract
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys15m728qxvtat337jdu2f0uk6pu905kktrxclgy36c0wd822tpxcmqfzew4d")), // old contract
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys1ul4msjc3mmaxsscdgdtjds85rg50qrepvrczp0ldgma5mm9xv8yqxhk8nu")), // old contract
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys1mx32w9tnfxv0z5j000750h8ver7qf3xpj09w3uzvsr3hq68f4hxqte4gam")), // old contract
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys14zykjnz94dr9nj4v2yzpvnlrw5uurk5h7d5w0wug902vxdynm6xsue684e")), // old contract
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys175r6y463k8cdcte6dzrxydxnwfkhz9afdghzcjxxhzfmm6rgu64qdp9z37")), // old contract
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys1jyhyqjxf3pc7vzwyqhwe53up5pj0e53zw3xu2589uqgkvqngswnqtxfw4e")), // old contract
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys14see2dq4nu37yk9qhjn2laqxrmzzjyxwhfgnxw4nuzpm7vc6ztysxjv4p5")), // old contract
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys15qe27v4z7j78g5g4ak2ftftky3c078zvtr9qtv5lhxwc54ccf4asggmyyp")), // old contract
wasmtypes.GetContractStorePrefix(sdk.MustAccAddressFromBech32("elys193dzg6ealfymax4pyrkge60swlr2tjupwegdemgalzhkkxc8kzyqh5qw9c")), // old contract
}

// Add old code keys to the list of prefixes to clear
for i := uint64(1); i < 675; i++ {
codeKey := wasmtypes.GetCodeKey(i)
// append the code key to the prefixes
prefixes = append(prefixes, codeKey)
}

// Clear all keys in the store
for _, prefix := range prefixes {
iter := sdk.KVStorePrefixIterator(store, prefix)
defer iter.Close()

for ; iter.Valid(); iter.Next() {
store.Delete(iter.Key())
}
}
}

return app.mm.RunMigrations(ctx, app.configurator, vm)
},
)
Expand Down
13 changes: 13 additions & 0 deletions proto/elys/stablestake/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ syntax = "proto3";
package elys.stablestake;

import "gogoproto/gogo.proto";
import "elys/stablestake/params.proto";

option go_package = "github.com/elys-network/elys/x/stablestake/types";

// Msg defines the Msg service.
service Msg {
rpc Bond(MsgBond) returns (MsgBondResponse);
rpc Unbond(MsgUnbond) returns (MsgUnbondResponse);
rpc UpdateParams (MsgUpdateParams ) returns (MsgUpdateParamsResponse );
}
message MsgBond {
string creator = 1;
Expand All @@ -31,3 +33,14 @@ message MsgUnbond {

message MsgUnbondResponse {}

message MsgUpdateParams {

// authority is the address that controls the module (defaults to x/gov unless
// overwritten).
string authority = 1;

// NOTE: All parameters must be supplied.
Params params = 2;
}

message MsgUpdateParamsResponse {}
3 changes: 3 additions & 0 deletions testutil/keeper/stablestake.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/cosmos/cosmos-sdk/store"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
typesparams "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/elys-network/elys/x/stablestake/keeper"
"github.com/elys-network/elys/x/stablestake/types"
Expand All @@ -29,6 +30,7 @@ func StablestakeKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {

registry := codectypes.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(registry)
govAddress := sdk.AccAddress(address.Module("gov"))

paramsSubspace := typesparams.NewSubspace(cdc,
types.Amino,
Expand All @@ -40,6 +42,7 @@ func StablestakeKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
cdc,
storeKey,
memStoreKey,
govAddress.String(),
paramsSubspace,
nil,
nil,
Expand Down
49 changes: 49 additions & 0 deletions x/leveragelp/spec/07_pool_status.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!--
order: 6
-->

### Pool Status

#### Overview

Managing pool status is crucial. Two key states are whether a pool is enabled or closed.

#### Pool Status Functions

```go
func (k Keeper) IsPoolEnabled(ctx sdk.Context, poolId uint64) bool {
pool, found := k.GetPool(ctx, poolId)
if (!found) {
pool = types.NewPool(poolId)
k.SetPool(ctx, pool)
}
return pool.Enabled
}

func (k Keeper) IsPoolClosed(ctx sdk.Context, poolId uint64) bool {
pool, found := k.GetPool(ctx, poolId)
if (!found) {
pool = types.NewPool(poolId)
k.SetPool(ctx, pool)
}
return pool.Closed
}
```

#### Functionality

1. **IsPoolEnabled**:

- Checks if a pool is enabled.
- If not found, initializes and sets a new pool.
- An enabled pool is processed by the module.

2. **IsPoolClosed**:
- Checks if a pool is closed.
- If not found, initializes and sets a new pool.
- A closed pool prevents new positions but allows existing ones to be processed.

#### Key Differences

- **Enabled**: The pool is either processed or excluded entirely.
- **Closed**: Only affects the opening of new positions; existing positions continue as usual.
1 change: 1 addition & 0 deletions x/leveragelp/spec/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ For more detailed information, please refer to the individual sections listed in
4. **[Endpoints](04_endpoints.md)**
5. **[CLI](05_cli.md)**
6. **[Position Workflow](06_position_workflow.md)**
7. **[Pool Status](07_pool_status.md)**
49 changes: 49 additions & 0 deletions x/perpetual/spec/07_pool_status.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!--
order: 6
-->

### Pool Status

#### Overview

Managing pool status is crucial. Two key states are whether a pool is enabled or closed.

#### Pool Status Functions

```go
func (k Keeper) IsPoolEnabled(ctx sdk.Context, poolId uint64) bool {
pool, found := k.GetPool(ctx, poolId)
if (!found) {
pool = types.NewPool(poolId)
k.SetPool(ctx, pool)
}
return pool.Enabled
}

func (k Keeper) IsPoolClosed(ctx sdk.Context, poolId uint64) bool {
pool, found := k.GetPool(ctx, poolId)
if (!found) {
pool = types.NewPool(poolId)
k.SetPool(ctx, pool)
}
return pool.Closed
}
```

#### Functionality

1. **IsPoolEnabled**:

- Checks if a pool is enabled.
- If not found, initializes and sets a new pool.
- An enabled pool is processed by the module.

2. **IsPoolClosed**:
- Checks if a pool is closed.
- If not found, initializes and sets a new pool.
- A closed pool prevents new positions but allows existing ones to be processed.

#### Key Differences

- **Enabled**: The pool is either processed or excluded entirely.
- **Closed**: Only affects the opening of new positions; existing positions continue as usual.
121 changes: 21 additions & 100 deletions x/perpetual/spec/README.md
Original file line number Diff line number Diff line change
@@ -1,108 +1,29 @@
<!--
order: 1
-->
# Perpetual module

# Concepts
The `perpetual` module in the Elys Network facilitates perpetual trading, allowing users to open and close leveraged positions on various assets without expiry dates. Positions, either long or short, are determined by the leverage applied and the amount of collateral provided. Leverage allows traders to borrow funds to open larger positions, amplifying potential profits and losses.

The `perpetual` module in the Elys Network facilitates perpetual trading, allowing users to open and close positions on various assets. This guide provides an overview of the key concepts and mechanisms involved in the perpetual module.
Collateral acts as a security deposit to cover potential losses, and if it falls below the maintenance margin, the position may be liquidated. The safety factor is a threshold to keep positions open, and position health indicates the risk level of a position. Liquidation occurs when the position's value drops below the safety factor, ensuring platform stability.

## Key Concepts
The funding rate is a periodic payment exchanged between long and short positions to align contract prices with underlying asset prices. Whitelisting controls access to the module, allowing only trusted participants to trade. The module has configurable parameters, such as leverage limits and interest rates, adjustable through governance proposals to maintain efficiency and security.

### Perpetual Trading
## Key Features

Perpetual trading allows users to trade assets with leverage without the need for expiry dates on their positions. This type of trading is popular in the cryptocurrency market as it offers flexibility and continuous trading opportunities.
- **Perpetual Trading**: Trade assets with leverage without expiry dates.
- **Positions**: Open long or short leveraged positions based on collateral and leverage.
- **Leverage**: Borrow funds to open larger positions, amplifying profits and losses.
- **Collateral**: Security deposit to cover potential losses and prevent liquidation.
- **Safety Factor**: Threshold to keep positions open and prevent liquidation.
- **Position Health**: Metric indicating the risk level of a position.
- **Liquidation**: Forcibly close positions below the safety factor to prevent further losses.

### Positions
For more detailed information, please refer to the individual sections listed in the contents below.

A position in perpetual trading represents an open contract on an asset. Positions can be either long (betting that the asset price will rise) or short (betting that the asset price will fall). The size of the position is determined by the leverage applied and the amount of collateral provided.
## Contents

### Leverage

Leverage allows traders to open positions larger than their collateral by borrowing funds. For example, with 5x leverage, a trader can open a position five times the size of their collateral. While leverage amplifies potential profits, it also increases potential losses.

### Collateral

Collateral is the amount of assets locked to open a leveraged position. It acts as a security deposit to cover potential losses. If the value of the position falls below the maintenance margin, the position may be liquidated to prevent further losses.

### Safety Factor

The safety factor is the threshold to keep a position open. If the position health value falls below this threshold, the position may be subject to liquidation.

### Position Health

Position health is a metric that indicates the risk level of a position. It is calculated based on the position's value, leverage, and collateral. Monitoring position health helps prevent excessive risk-taking and ensures the stability of the perpetual trading system.

### Liquidation

Liquidation occurs when a position's value drops below the safety factor. The position is forcibly closed to prevent further losses. This mechanism ensures the stability of the perpetual trading system and protects the platform from significant losses.

### Funding Rate

The funding rate is a periodic payment exchanged between long and short positions. It ensures that the perpetual contract price closely tracks the underlying asset price. When the funding rate is positive, longs pay shorts, and when it is negative, shorts pay longs.

### Whitelisting

Whitelisting is a mechanism to control access to the perpetual module. Only addresses that are whitelisted can participate in trading. This helps maintain the security and integrity of the platform by allowing only trusted participants.

### Parameters

The perpetual module has several configurable parameters that govern its operation. These include leverage limits, interest rates, maintenance margins, and more. These parameters can be updated through governance proposals to adapt to changing market conditions and ensure the module's efficiency and security.

## Perpetual Module Overview

The perpetual module supports perpetual trading on molecule token pools. Initially, isolated perpetual trading is supported, with plans to include cross perpetual trading in the future.

### Pools

Perpetual trading utilizes AMM (Automated Market Maker) pools and maintains position records. When a trader closes a position or it is liquidated, pool tokens are transferred to the perpetual trader for profit and loss (P&L).

### Perpetual Limits

Perpetual trading limits are based on the pool size. To maintain pool health, perpetual positions are restricted to ensure that no more than 50% of the pool's assets are borrowed.

### Race Condition Between AMM and Perpetual

Due to the possibility of pool balance insufficiency, a healthy buffer must be maintained when setting perpetual positions. The position should be auto-closed before the pool becomes insufficient to cover it. Any action affecting the position's health should trigger position closing.

### Risks

Perpetual trading will not be offered on shallow pools to mitigate risk.

### Oracle

The oracle should use average prices to prevent large liquidations caused by sudden, short-term price dumps. In cases where multiple oracle price sources are used, exceptions may need to be made for anomalies such as massive candle spikes from one source.

### Reference Codebases for Perpetual

- To Be Determined (TBD)

### Notes

- The perpetual code will serve as the base for LP leveraging, with the primary difference being that perpetual trading borrows from the pool liquidity itself, while LP leveraging borrows from base currency deposits.
- Cross perpetual trading will enable interactions between perpetual positions and LP positions once implemented.

## Transaction Commands

The perpetual module supports various transaction commands for managing positions and parameters. Key commands include:

- `open`: Opens a new perpetual position.
- `close`: Closes an existing perpetual position.
- `whitelist`: Adds an address to the whitelist.
- `dewhitelist`: Removes an address from the whitelist.
- `update-params`: Updates the module parameters through a governance proposal.

## Query Commands

Users can query various aspects of the perpetual module using the following commands:

- `params`: Retrieves the current parameters of the module.
- `get-positions`: Lists all open positions.
- `get-positions-by-pool`: Lists positions for a specific pool.
- `get-positions-for-address`: Lists positions for a specific address.
- `get-status`: Retrieves the current status of the module.
- `get-whitelist`: Lists all whitelisted addresses.
- `is-whitelisted`: Checks if a specific address is whitelisted.
- `list-pool`: Lists all available pools.
- `show-pool`: Retrieves details of a specific pool.
- `get-mtp`: Retrieves details of a specific margin trading position (MTP).
- `open-estimation`: Provides an estimation for opening a position.
1. **[Concepts](01_concepts.md)**
2. **[Mechanisms](02_mechanisms.md)**
3. **[Usage](03_usage.md)**
4. **[Keeper](04_keeper.md)**
5. **[Protobuf Definitions](05_protobuf_definitions.md)**
6. **[Functions](06_functions.md)**
7. **[Pool Status](07_pool_status.md)**
8 changes: 8 additions & 0 deletions x/stablestake/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type (
cdc codec.BinaryCodec
storeKey storetypes.StoreKey
memKey storetypes.StoreKey
authority string
paramstore paramtypes.Subspace
bk types.BankKeeper
commitmentKeeper *commitmentkeeper.Keeper
Expand All @@ -29,6 +30,7 @@ func NewKeeper(
cdc codec.BinaryCodec,
storeKey,
memKey storetypes.StoreKey,
authority string,
ps paramtypes.Subspace,
bk types.BankKeeper,
commitmentKeeper *commitmentkeeper.Keeper,
Expand All @@ -39,10 +41,16 @@ func NewKeeper(
ps = ps.WithKeyTable(types.ParamKeyTable())
}

// ensure that authority is a valid AccAddress
if _, err := sdk.AccAddressFromBech32(authority); err != nil {
panic("authority is not a valid acc address")
}

return &Keeper{
cdc: cdc,
storeKey: storeKey,
memKey: memKey,
authority: authority,
paramstore: ps,
bk: bk,
commitmentKeeper: commitmentKeeper,
Expand Down
Loading

0 comments on commit 2472c14

Please sign in to comment.