Skip to content

Commit 1e0f366

Browse files
ivanovpetrPetr IvanovYurist-85kioqq
authored
[v1.7.2] Liquid vesting module (#275)
* 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 <[email protected]> Co-authored-by: Yuri Surbashev <[email protected]> Co-authored-by: Evgeniy Abramov <[email protected]>
1 parent 20dfe01 commit 1e0f366

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+6330
-75
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ DIFF_TAG=$(shell git rev-list --tags="v*" --max-count=1 --not $(shell git rev-li
66
DEFAULT_TAG=$(shell git rev-list --tags="v*" --max-count=1)
77
# VERSION ?= $(shell echo $(shell git describe --tags $(or $(DIFF_TAG), $(DEFAULT_TAG))) | sed 's/^v//')
88

9-
VERSION := "1.7.1"
9+
VERSION := "1.7.2"
1010
CBFTVERSION := $(shell go list -m github.com/cometbft/cometbft | sed 's:.* ::')
1111
COMMIT := $(shell git log -1 --format='%H')
1212
LEDGER_ENABLED ?= true

app/app.go

+33-3
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ import (
146146
erc20client "github.com/haqq-network/haqq/x/erc20/client"
147147
erc20keeper "github.com/haqq-network/haqq/x/erc20/keeper"
148148
erc20types "github.com/haqq-network/haqq/x/erc20/types"
149+
"github.com/haqq-network/haqq/x/liquidvesting"
150+
liquidvestingkeeper "github.com/haqq-network/haqq/x/liquidvesting/keeper"
151+
liquidvestingtypes "github.com/haqq-network/haqq/x/liquidvesting/types"
149152
"github.com/haqq-network/haqq/x/vesting"
150153
vestingkeeper "github.com/haqq-network/haqq/x/vesting/keeper"
151154
vestingtypes "github.com/haqq-network/haqq/x/vesting/types"
@@ -157,6 +160,7 @@ import (
157160
v164 "github.com/haqq-network/haqq/app/upgrades/v1.6.4"
158161
v170 "github.com/haqq-network/haqq/app/upgrades/v1.7.0"
159162
v171 "github.com/haqq-network/haqq/app/upgrades/v1.7.1"
163+
v172 "github.com/haqq-network/haqq/app/upgrades/v1.7.2"
160164

161165
// NOTE: override ICS20 keeper to support IBC transfers of ERC20 tokens
162166
"github.com/haqq-network/haqq/x/ibc/transfer"
@@ -232,6 +236,7 @@ var (
232236
erc20.AppModuleBasic{},
233237
epochs.AppModuleBasic{},
234238
consensus.AppModuleBasic{},
239+
liquidvesting.AppModuleBasic{},
235240
)
236241

237242
// module account permissions
@@ -247,6 +252,7 @@ var (
247252
erc20types.ModuleName: {authtypes.Minter, authtypes.Burner},
248253
coinomicstypes.ModuleName: {authtypes.Minter},
249254
vestingtypes.ModuleName: nil, // Add vesting module account
255+
liquidvestingtypes.ModuleName: {authtypes.Minter, authtypes.Burner},
250256
}
251257

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

309315
// Evmos keepers
310-
Erc20Keeper erc20keeper.Keeper
311-
EpochsKeeper epochskeeper.Keeper
312-
VestingKeeper vestingkeeper.Keeper
316+
Erc20Keeper erc20keeper.Keeper
317+
EpochsKeeper epochskeeper.Keeper
318+
VestingKeeper vestingkeeper.Keeper
319+
LiquidVestingKeeper liquidvestingkeeper.Keeper
313320

314321
// Haqq keepers
315322
CoinomicsKeeper coinomicskeeper.Keeper
@@ -384,6 +391,7 @@ func NewHaqq(
384391
epochstypes.StoreKey, vestingtypes.StoreKey,
385392
// haqq keys
386393
coinomicstypes.StoreKey,
394+
liquidvestingtypes.StoreKey,
387395
)
388396

389397
// Add the EVM transient store key
@@ -528,6 +536,11 @@ func NewHaqq(
528536
app.AccountKeeper, app.BankKeeper, app.EvmKeeper, app.StakingKeeper,
529537
)
530538

539+
app.LiquidVestingKeeper = liquidvestingkeeper.NewKeeper(
540+
keys[vestingtypes.StoreKey], appCodec, app.GetSubspace(liquidvestingtypes.ModuleName),
541+
app.AccountKeeper, app.BankKeeper, app.Erc20Keeper, app.VestingKeeper,
542+
)
543+
531544
epochsKeeper := epochskeeper.NewKeeper(appCodec, keys[epochstypes.StoreKey])
532545
app.EpochsKeeper = *epochsKeeper.SetHooks(
533546
epochskeeper.NewMultiEpochHooks(
@@ -649,6 +662,7 @@ func NewHaqq(
649662
erc20.NewAppModule(app.Erc20Keeper, app.AccountKeeper, app.GetSubspace(erc20types.ModuleName)),
650663
epochs.NewAppModule(appCodec, app.EpochsKeeper),
651664
vesting.NewAppModule(app.VestingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
665+
liquidvesting.NewAppModule(appCodec, app.LiquidVestingKeeper, app.AccountKeeper, app.BankKeeper, app.Erc20Keeper),
652666

653667
// Haqq app modules
654668
coinomics.NewAppModule(app.CoinomicsKeeper, app.AccountKeeper, app.StakingKeeper),
@@ -687,6 +701,7 @@ func NewHaqq(
687701
erc20types.ModuleName,
688702
coinomicstypes.ModuleName,
689703
consensusparamtypes.ModuleName,
704+
liquidvestingtypes.ModuleName,
690705
)
691706

692707
// NOTE: fee market module must go last in order to retrieve the block gas used.
@@ -721,6 +736,7 @@ func NewHaqq(
721736
// Haqq modules
722737
coinomicstypes.ModuleName,
723738
consensusparamtypes.ModuleName,
739+
liquidvestingtypes.ModuleName,
724740
)
725741

726742
// NOTE: The genutils module must occur after staking so that pools are
@@ -755,6 +771,7 @@ func NewHaqq(
755771
upgradetypes.ModuleName,
756772
// Evmos modules
757773
vestingtypes.ModuleName,
774+
liquidvestingtypes.ModuleName,
758775
coinomicstypes.ModuleName,
759776
erc20types.ModuleName,
760777
epochstypes.ModuleName,
@@ -1118,6 +1135,7 @@ func initParamsKeeper(
11181135
paramsKeeper.Subspace(erc20types.ModuleName)
11191136
// haqq subspaces
11201137
paramsKeeper.Subspace(coinomicstypes.ModuleName)
1138+
paramsKeeper.Subspace(liquidvestingtypes.ModuleName)
11211139

11221140
return paramsKeeper
11231141
}
@@ -1196,6 +1214,12 @@ func (app *Haqq) setupUpgradeHandlers() {
11961214
v171.CreateUpgradeHandler(app.mm, app.configurator),
11971215
)
11981216

1217+
// v1.7.2 Add Liquid Vesting Module
1218+
app.UpgradeKeeper.SetUpgradeHandler(
1219+
v172.UpgradeName,
1220+
v172.CreateUpgradeHandler(app.mm, app.configurator),
1221+
)
1222+
11991223
// When a planned update height is reached, the old binary will panic
12001224
// writing on disk the height and name of the update that triggered it
12011225
// This will read that value, and execute the preparations for the upgrade.
@@ -1224,6 +1248,12 @@ func (app *Haqq) setupUpgradeHandlers() {
12241248
crisistypes.ModuleName,
12251249
},
12261250
}
1251+
case v172.UpgradeName:
1252+
storeUpgrades = &storetypes.StoreUpgrades{
1253+
Added: []string{
1254+
liquidvestingtypes.ModuleName,
1255+
},
1256+
}
12271257
}
12281258

12291259
if storeUpgrades != nil {

app/upgrades/v1.7.2/constants.go

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package v172
2+
3+
const (
4+
// UpgradeName is the shared upgrade plan name for mainnet and testnet
5+
UpgradeName = "v1.7.2"
6+
)

app/upgrades/v1.7.2/upgrades.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package v172
2+
3+
import (
4+
sdk "github.com/cosmos/cosmos-sdk/types"
5+
"github.com/cosmos/cosmos-sdk/types/module"
6+
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
7+
)
8+
9+
// CreateUpgradeHandler creates an SDK upgrade handler for v1.7.2
10+
func CreateUpgradeHandler(
11+
mm *module.Manager,
12+
configurator module.Configurator,
13+
) upgradetypes.UpgradeHandler {
14+
return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
15+
logger := ctx.Logger()
16+
logger.Info("run migration v1.7.2")
17+
18+
return mm.RunMigrations(ctx, configurator, vm)
19+
}
20+
}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
syntax = "proto3";
2+
package haqq.liquidvesting.v1;
3+
4+
import "gogoproto/gogo.proto";
5+
6+
option go_package = "github.com/haqq-network/haqq/x/liquidvesting/types";
7+
8+
// GenesisState defines the liquidvesting module's genesis state.
9+
message GenesisState {
10+
// params defines all the paramaters of the module.
11+
Params params = 1 [ (gogoproto.nullable) = false ];
12+
}
13+
14+
// Params holds parameters for the liquidvesting module.
15+
message Params {
16+
string minimum_liquidation_amount = 1 [
17+
(gogoproto.customtype) = "cosmossdk.io/math.Int",
18+
(gogoproto.nullable) = false
19+
];
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
syntax = "proto3";
2+
package haqq.liquidvesting.v1;
3+
4+
import "amino/amino.proto";
5+
import "gogoproto/gogo.proto";
6+
import "cosmos/vesting/v1beta1/vesting.proto";
7+
import "google/protobuf/timestamp.proto";
8+
import "cosmos/base/v1beta1/coin.proto";
9+
10+
11+
option go_package = "github.com/haqq-network/haqq/x/liquidvesting/types";
12+
13+
// Denom represents liquid token bonded to some specific vesting schedule
14+
message Denom {
15+
// base_denom main identifier for the denom, used to query it from store.
16+
string base_denom = 1;
17+
// display_denom identifier used for display name for broad audience
18+
string display_denom = 2;
19+
// original_denom which liquid denom derived from
20+
string original_denom = 3;
21+
// start date
22+
google.protobuf.Timestamp start_time = 4
23+
[ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ];
24+
// end_date
25+
google.protobuf.Timestamp end_time = 5
26+
[ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ];
27+
// lockup periods
28+
repeated cosmos.vesting.v1beta1.Period lockup_periods = 6 [
29+
(gogoproto.nullable) = false,
30+
(gogoproto.castrepeated) =
31+
"github.com/cosmos/cosmos-sdk/x/auth/vesting/types.Periods"
32+
];
33+
}
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
syntax = "proto3";
2+
package haqq.liquidvesting.v1;
3+
4+
import "amino/amino.proto";
5+
import "gogoproto/gogo.proto";
6+
import "google/api/annotations.proto";
7+
import "cosmos/base/query/v1beta1/pagination.proto";
8+
import "haqq/liquidvesting/v1/liquidvesting.proto";
9+
10+
option go_package = "github.com/haqq-network/haqq/x/liquidvesting/types";
11+
12+
// Query defines the gRPC querier service.
13+
service Query {
14+
// Denom queries liquid vesting token info by denom
15+
rpc Denom(QueryDenomRequest) returns (QueryDenomResponse) {
16+
option (google.api.http).get = "/haqq/liquidvesting/v1/denom";
17+
};
18+
// Denoms queries liquid vesting tokens info
19+
rpc Denoms(QueryDenomsRequest) returns (QueryDenomsResponse) {
20+
option (google.api.http).get = "/haqq/liquidvesting/v1/denoms";
21+
};
22+
}
23+
24+
// QueryDenomRequest is request fo Denom rpc method
25+
message QueryDenomRequest {
26+
// denom is liquidated vesting token
27+
string denom = 1;
28+
}
29+
30+
// QueryDenomResponse is response for Denom rpc method
31+
message QueryDenomResponse {
32+
// denom is liquidated vesting token
33+
Denom denom = 1 [
34+
(gogoproto.nullable) = false,
35+
(amino.dont_omitempty) = true
36+
];
37+
}
38+
39+
// QueryDenomsRequest is request for Denoms rpc method
40+
message QueryDenomsRequest {
41+
// pagination defines an optional pagination for the request.
42+
cosmos.base.query.v1beta1.PageRequest pagination = 1;
43+
}
44+
45+
// QueryDenomsResponse is response for Denoms rpc method
46+
message QueryDenomsResponse {
47+
// denoms are liquidated vesting tokens
48+
repeated Denom denoms = 1 [
49+
(gogoproto.nullable) = false,
50+
(amino.dont_omitempty) = true
51+
];
52+
53+
// pagination defines the pagination in the response.
54+
cosmos.base.query.v1beta1.PageResponse pagination = 2;
55+
}

proto/haqq/liquidvesting/v1/tx.proto

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
syntax = "proto3";
2+
package haqq.liquidvesting.v1;
3+
4+
import "amino/amino.proto";
5+
import "gogoproto/gogo.proto";
6+
import "google/api/annotations.proto";
7+
import "cosmos/base/v1beta1/coin.proto";
8+
9+
10+
option go_package = "github.com/haqq-network/haqq/x/liquidvesting/types";
11+
12+
// Msg defines the Msg service.
13+
service Msg {
14+
// Liquidate transforms specified amount of tokens locked on vesting account into a new liquid token
15+
rpc Liquidate(MsgLiquidate) returns (MsgLiquidateResponse) {
16+
option (google.api.http).post = "/haqq/liquidvesting/v1/tx/liquidate";
17+
};
18+
19+
// Redeem burns liquid token and deposits corresponding amount of vesting token to the specified account
20+
rpc Redeem (MsgRedeem) returns (MsgRedeemResponse) {
21+
option (google.api.http).post = "/haqq/liquidvesting/v1/tx/redeem";
22+
};
23+
}
24+
25+
// MsgLiquidate represents message to liquidate arbitrary amount of tokens locked in vesting
26+
message MsgLiquidate {
27+
// account for liquidation of locked vesting tokens
28+
string liquidate_from = 1;
29+
// account to send resulted liquid token
30+
string liquidate_to = 2;
31+
// amount of tokens subject for liquidation
32+
cosmos.base.v1beta1.Coin amount = 3 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true];
33+
}
34+
35+
// MsgLiquidateResponse defines the Msg/Liquidate response type
36+
message MsgLiquidateResponse {}
37+
38+
// MsgLiquidate represents message to redeem arbitrary amount of liquid vesting tokens
39+
message MsgRedeem {
40+
string redeem_from = 1;
41+
// destination address for vesting tokens
42+
string redeem_to = 2;
43+
// amount of vesting tokens to redeem from liquidation module
44+
cosmos.base.v1beta1.Coin amount = 3 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true];
45+
}
46+
47+
// MsgRedeemResponse defines the Msg/Redeem response type
48+
message MsgRedeemResponse {}

tests/e2e/upgrade/manager.go

-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ func (m *Manager) RunNode(node *Node) error {
132132
return nil
133133
},
134134
)
135-
136135
if err != nil {
137136
stdOut, stdErr, _ := m.GetLogs(resource.Container.ID)
138137
return fmt.Errorf(

0 commit comments

Comments
 (0)