Skip to content

Commit

Permalink
[v1.7.2] Liquid vesting module (#275)
Browse files Browse the repository at this point in the history
* scaffold liquidvesting module

* fix linter

* fix linter

* outline liquidvesting proto interface

* liquidate tx implementation

* increase test coverage for liquidvesting module

* implement liquid denom queries

* add tests for liquidate handler and some other stuff

* refactor convert into vesting account

* redeem handler first iteration

* fix build

* redeem tests and bug fixes

* adds erc20 checks

* add review fixes

* add review fixes pt 2

* minor review fixes

* add module param minimumLiquidationAmount

* add auto erc20 conversion during redeem

* fix linter

* disable token pair after it is went down to zero total supply

* add enable check on token pair

* fix lint

* fix lint

* chore: add upgrade handler

* change default param

* change default param

* fix: cli query denoms for liquid vesting

* fix: msg_server reduce vesting periods

* chore: add force conversion into erc20 tokens on liquidation

* chore: fix tests

* chore(liquidation): update store key for param

* chore: inlcude escrowed liquid vesting balance into total locked stats

---------

Co-authored-by: Petr Ivanov <petr.ivanov@tendermint.com>
Co-authored-by: Yuri Surbashev <yurist@insport.net>
Co-authored-by: Evgeniy Abramov <i@kio.ninja>
  • Loading branch information
4 people committed Feb 12, 2024
1 parent 20dfe01 commit 1e0f366
Show file tree
Hide file tree
Showing 46 changed files with 6,330 additions and 75 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ DIFF_TAG=$(shell git rev-list --tags="v*" --max-count=1 --not $(shell git rev-li
DEFAULT_TAG=$(shell git rev-list --tags="v*" --max-count=1)
# VERSION ?= $(shell echo $(shell git describe --tags $(or $(DIFF_TAG), $(DEFAULT_TAG))) | sed 's/^v//')

VERSION := "1.7.1"
VERSION := "1.7.2"
CBFTVERSION := $(shell go list -m github.com/cometbft/cometbft | sed 's:.* ::')
COMMIT := $(shell git log -1 --format='%H')
LEDGER_ENABLED ?= true
Expand Down
36 changes: 33 additions & 3 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ import (
erc20client "github.com/haqq-network/haqq/x/erc20/client"
erc20keeper "github.com/haqq-network/haqq/x/erc20/keeper"
erc20types "github.com/haqq-network/haqq/x/erc20/types"
"github.com/haqq-network/haqq/x/liquidvesting"
liquidvestingkeeper "github.com/haqq-network/haqq/x/liquidvesting/keeper"
liquidvestingtypes "github.com/haqq-network/haqq/x/liquidvesting/types"
"github.com/haqq-network/haqq/x/vesting"
vestingkeeper "github.com/haqq-network/haqq/x/vesting/keeper"
vestingtypes "github.com/haqq-network/haqq/x/vesting/types"
Expand All @@ -157,6 +160,7 @@ import (
v164 "github.com/haqq-network/haqq/app/upgrades/v1.6.4"
v170 "github.com/haqq-network/haqq/app/upgrades/v1.7.0"
v171 "github.com/haqq-network/haqq/app/upgrades/v1.7.1"
v172 "github.com/haqq-network/haqq/app/upgrades/v1.7.2"

// NOTE: override ICS20 keeper to support IBC transfers of ERC20 tokens
"github.com/haqq-network/haqq/x/ibc/transfer"
Expand Down Expand Up @@ -232,6 +236,7 @@ var (
erc20.AppModuleBasic{},
epochs.AppModuleBasic{},
consensus.AppModuleBasic{},
liquidvesting.AppModuleBasic{},
)

// module account permissions
Expand All @@ -247,6 +252,7 @@ var (
erc20types.ModuleName: {authtypes.Minter, authtypes.Burner},
coinomicstypes.ModuleName: {authtypes.Minter},
vestingtypes.ModuleName: nil, // Add vesting module account
liquidvestingtypes.ModuleName: {authtypes.Minter, authtypes.Burner},
}

// module accounts that are allowed to receive tokens
Expand Down Expand Up @@ -307,9 +313,10 @@ type Haqq struct {
FeeMarketKeeper feemarketkeeper.Keeper

// Evmos keepers
Erc20Keeper erc20keeper.Keeper
EpochsKeeper epochskeeper.Keeper
VestingKeeper vestingkeeper.Keeper
Erc20Keeper erc20keeper.Keeper
EpochsKeeper epochskeeper.Keeper
VestingKeeper vestingkeeper.Keeper
LiquidVestingKeeper liquidvestingkeeper.Keeper

// Haqq keepers
CoinomicsKeeper coinomicskeeper.Keeper
Expand Down Expand Up @@ -384,6 +391,7 @@ func NewHaqq(
epochstypes.StoreKey, vestingtypes.StoreKey,
// haqq keys
coinomicstypes.StoreKey,
liquidvestingtypes.StoreKey,
)

// Add the EVM transient store key
Expand Down Expand Up @@ -528,6 +536,11 @@ func NewHaqq(
app.AccountKeeper, app.BankKeeper, app.EvmKeeper, app.StakingKeeper,
)

app.LiquidVestingKeeper = liquidvestingkeeper.NewKeeper(
keys[vestingtypes.StoreKey], appCodec, app.GetSubspace(liquidvestingtypes.ModuleName),
app.AccountKeeper, app.BankKeeper, app.Erc20Keeper, app.VestingKeeper,
)

epochsKeeper := epochskeeper.NewKeeper(appCodec, keys[epochstypes.StoreKey])
app.EpochsKeeper = *epochsKeeper.SetHooks(
epochskeeper.NewMultiEpochHooks(
Expand Down Expand Up @@ -649,6 +662,7 @@ func NewHaqq(
erc20.NewAppModule(app.Erc20Keeper, app.AccountKeeper, app.GetSubspace(erc20types.ModuleName)),
epochs.NewAppModule(appCodec, app.EpochsKeeper),
vesting.NewAppModule(app.VestingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
liquidvesting.NewAppModule(appCodec, app.LiquidVestingKeeper, app.AccountKeeper, app.BankKeeper, app.Erc20Keeper),

// Haqq app modules
coinomics.NewAppModule(app.CoinomicsKeeper, app.AccountKeeper, app.StakingKeeper),
Expand Down Expand Up @@ -687,6 +701,7 @@ func NewHaqq(
erc20types.ModuleName,
coinomicstypes.ModuleName,
consensusparamtypes.ModuleName,
liquidvestingtypes.ModuleName,
)

// NOTE: fee market module must go last in order to retrieve the block gas used.
Expand Down Expand Up @@ -721,6 +736,7 @@ func NewHaqq(
// Haqq modules
coinomicstypes.ModuleName,
consensusparamtypes.ModuleName,
liquidvestingtypes.ModuleName,
)

// NOTE: The genutils module must occur after staking so that pools are
Expand Down Expand Up @@ -755,6 +771,7 @@ func NewHaqq(
upgradetypes.ModuleName,
// Evmos modules
vestingtypes.ModuleName,
liquidvestingtypes.ModuleName,
coinomicstypes.ModuleName,
erc20types.ModuleName,
epochstypes.ModuleName,
Expand Down Expand Up @@ -1118,6 +1135,7 @@ func initParamsKeeper(
paramsKeeper.Subspace(erc20types.ModuleName)
// haqq subspaces
paramsKeeper.Subspace(coinomicstypes.ModuleName)
paramsKeeper.Subspace(liquidvestingtypes.ModuleName)

return paramsKeeper
}
Expand Down Expand Up @@ -1196,6 +1214,12 @@ func (app *Haqq) setupUpgradeHandlers() {
v171.CreateUpgradeHandler(app.mm, app.configurator),
)

// v1.7.2 Add Liquid Vesting Module
app.UpgradeKeeper.SetUpgradeHandler(
v172.UpgradeName,
v172.CreateUpgradeHandler(app.mm, app.configurator),
)

// When a planned update height is reached, the old binary will panic
// writing on disk the height and name of the update that triggered it
// This will read that value, and execute the preparations for the upgrade.
Expand Down Expand Up @@ -1224,6 +1248,12 @@ func (app *Haqq) setupUpgradeHandlers() {
crisistypes.ModuleName,
},
}
case v172.UpgradeName:
storeUpgrades = &storetypes.StoreUpgrades{
Added: []string{
liquidvestingtypes.ModuleName,
},
}
}

if storeUpgrades != nil {
Expand Down
6 changes: 6 additions & 0 deletions app/upgrades/v1.7.2/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package v172

const (
// UpgradeName is the shared upgrade plan name for mainnet and testnet
UpgradeName = "v1.7.2"
)
20 changes: 20 additions & 0 deletions app/upgrades/v1.7.2/upgrades.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package v172

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
)

// CreateUpgradeHandler creates an SDK upgrade handler for v1.7.2
func CreateUpgradeHandler(
mm *module.Manager,
configurator module.Configurator,
) upgradetypes.UpgradeHandler {
return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
logger := ctx.Logger()
logger.Info("run migration v1.7.2")

return mm.RunMigrations(ctx, configurator, vm)
}
}
20 changes: 20 additions & 0 deletions proto/haqq/liquidvesting/v1/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
syntax = "proto3";
package haqq.liquidvesting.v1;

import "gogoproto/gogo.proto";

option go_package = "github.com/haqq-network/haqq/x/liquidvesting/types";

// GenesisState defines the liquidvesting module's genesis state.
message GenesisState {
// params defines all the paramaters of the module.
Params params = 1 [ (gogoproto.nullable) = false ];
}

// Params holds parameters for the liquidvesting module.
message Params {
string minimum_liquidation_amount = 1 [
(gogoproto.customtype) = "cosmossdk.io/math.Int",
(gogoproto.nullable) = false
];
}
33 changes: 33 additions & 0 deletions proto/haqq/liquidvesting/v1/liquidvesting.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
syntax = "proto3";
package haqq.liquidvesting.v1;

import "amino/amino.proto";
import "gogoproto/gogo.proto";
import "cosmos/vesting/v1beta1/vesting.proto";
import "google/protobuf/timestamp.proto";
import "cosmos/base/v1beta1/coin.proto";


option go_package = "github.com/haqq-network/haqq/x/liquidvesting/types";

// Denom represents liquid token bonded to some specific vesting schedule
message Denom {
// base_denom main identifier for the denom, used to query it from store.
string base_denom = 1;
// display_denom identifier used for display name for broad audience
string display_denom = 2;
// original_denom which liquid denom derived from
string original_denom = 3;
// start date
google.protobuf.Timestamp start_time = 4
[ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ];
// end_date
google.protobuf.Timestamp end_time = 5
[ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ];
// lockup periods
repeated cosmos.vesting.v1beta1.Period lockup_periods = 6 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) =
"github.com/cosmos/cosmos-sdk/x/auth/vesting/types.Periods"
];
}
55 changes: 55 additions & 0 deletions proto/haqq/liquidvesting/v1/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
syntax = "proto3";
package haqq.liquidvesting.v1;

import "amino/amino.proto";
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "haqq/liquidvesting/v1/liquidvesting.proto";

option go_package = "github.com/haqq-network/haqq/x/liquidvesting/types";

// Query defines the gRPC querier service.
service Query {
// Denom queries liquid vesting token info by denom
rpc Denom(QueryDenomRequest) returns (QueryDenomResponse) {
option (google.api.http).get = "/haqq/liquidvesting/v1/denom";
};
// Denoms queries liquid vesting tokens info
rpc Denoms(QueryDenomsRequest) returns (QueryDenomsResponse) {
option (google.api.http).get = "/haqq/liquidvesting/v1/denoms";
};
}

// QueryDenomRequest is request fo Denom rpc method
message QueryDenomRequest {
// denom is liquidated vesting token
string denom = 1;
}

// QueryDenomResponse is response for Denom rpc method
message QueryDenomResponse {
// denom is liquidated vesting token
Denom denom = 1 [
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true
];
}

// QueryDenomsRequest is request for Denoms rpc method
message QueryDenomsRequest {
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}

// QueryDenomsResponse is response for Denoms rpc method
message QueryDenomsResponse {
// denoms are liquidated vesting tokens
repeated Denom denoms = 1 [
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true
];

// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
48 changes: 48 additions & 0 deletions proto/haqq/liquidvesting/v1/tx.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
syntax = "proto3";
package haqq.liquidvesting.v1;

import "amino/amino.proto";
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "cosmos/base/v1beta1/coin.proto";


option go_package = "github.com/haqq-network/haqq/x/liquidvesting/types";

// Msg defines the Msg service.
service Msg {
// Liquidate transforms specified amount of tokens locked on vesting account into a new liquid token
rpc Liquidate(MsgLiquidate) returns (MsgLiquidateResponse) {
option (google.api.http).post = "/haqq/liquidvesting/v1/tx/liquidate";
};

// Redeem burns liquid token and deposits corresponding amount of vesting token to the specified account
rpc Redeem (MsgRedeem) returns (MsgRedeemResponse) {
option (google.api.http).post = "/haqq/liquidvesting/v1/tx/redeem";
};
}

// MsgLiquidate represents message to liquidate arbitrary amount of tokens locked in vesting
message MsgLiquidate {
// account for liquidation of locked vesting tokens
string liquidate_from = 1;
// account to send resulted liquid token
string liquidate_to = 2;
// amount of tokens subject for liquidation
cosmos.base.v1beta1.Coin amount = 3 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}

// MsgLiquidateResponse defines the Msg/Liquidate response type
message MsgLiquidateResponse {}

// MsgLiquidate represents message to redeem arbitrary amount of liquid vesting tokens
message MsgRedeem {
string redeem_from = 1;
// destination address for vesting tokens
string redeem_to = 2;
// amount of vesting tokens to redeem from liquidation module
cosmos.base.v1beta1.Coin amount = 3 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}

// MsgRedeemResponse defines the Msg/Redeem response type
message MsgRedeemResponse {}
1 change: 0 additions & 1 deletion tests/e2e/upgrade/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ func (m *Manager) RunNode(node *Node) error {
return nil
},
)

if err != nil {
stdOut, stdErr, _ := m.GetLogs(resource.Container.ID)
return fmt.Errorf(
Expand Down
Loading

0 comments on commit 1e0f366

Please sign in to comment.