Skip to content

Commit c7800ac

Browse files
colmaziaRogerKSI
andauthored
[Feeds] integrate restake module (#182)
* first draft of restake module * add restake module into app * add keys and locks * first version for distribution logic * finish logic's first version * fix lint and test * refactor and optimize * add genesis * add events * fix * fix module account * fix from spec * key format * adjust comment * separate module account to key account for keeping rewards * add pagination for query path * fix claim reward * fix precision * fix reward debt sign * add gomock * fix double set hooks * implement restake module in feeds module * fix from comments --------- Co-authored-by: Kitipong Sirirueangsakul <[email protected]>
1 parent 4000e34 commit c7800ac

Some content is hidden

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

44 files changed

+9336
-101
lines changed

app/app.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ import (
129129
"github.com/bandprotocol/chain/v2/x/oracle"
130130
oraclekeeper "github.com/bandprotocol/chain/v2/x/oracle/keeper"
131131
oracletypes "github.com/bandprotocol/chain/v2/x/oracle/types"
132+
"github.com/bandprotocol/chain/v2/x/restake"
133+
restakekeeper "github.com/bandprotocol/chain/v2/x/restake/keeper"
134+
restaketypes "github.com/bandprotocol/chain/v2/x/restake/types"
132135
)
133136

134137
const (
@@ -178,6 +181,7 @@ var (
178181
oracle.AppModuleBasic{},
179182
feeds.AppModuleBasic{},
180183
globalfee.AppModule{},
184+
restake.AppModuleBasic{},
181185
)
182186
// module account permissions
183187
maccPerms = map[string][]string{
@@ -189,6 +193,7 @@ var (
189193
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
190194
govtypes.ModuleName: {authtypes.Burner},
191195
ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner},
196+
restaketypes.ModuleName: nil,
192197
}
193198

194199
Upgrades = []upgrades.Upgrade{v2_6.Upgrade}
@@ -291,6 +296,7 @@ func NewBandApp(
291296
oracletypes.StoreKey,
292297
feedstypes.StoreKey,
293298
globalfeetypes.StoreKey,
299+
restaketypes.StoreKey,
294300
)
295301
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey)
296302
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
@@ -419,6 +425,16 @@ func NewBandApp(
419425
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
420426
)
421427

428+
app.RestakeKeeper = restakekeeper.NewKeeper(
429+
appCodec,
430+
keys[restaketypes.StoreKey],
431+
authtypes.FeeCollectorName,
432+
app.AccountKeeper,
433+
app.BankKeeper,
434+
app.StakingKeeper,
435+
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
436+
)
437+
422438
// create IBC Keeper
423439
app.IBCKeeper = ibckeeper.NewKeeper(
424440
appCodec,
@@ -531,6 +547,7 @@ func NewBandApp(
531547
keys[feedstypes.StoreKey],
532548
app.OracleKeeper,
533549
app.StakingKeeper,
550+
app.RestakeKeeper,
534551
app.AuthzKeeper,
535552
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
536553
)
@@ -539,7 +556,7 @@ func NewBandApp(
539556
stakingtypes.NewMultiStakingHooks(
540557
app.DistrKeeper.Hooks(),
541558
app.SlashingKeeper.Hooks(),
542-
app.FeedsKeeper.Hooks(),
559+
app.RestakeKeeper.Hooks(),
543560
),
544561
)
545562

@@ -634,6 +651,7 @@ func NewBandApp(
634651
oracleModule,
635652
feeds.NewAppModule(appCodec, app.FeedsKeeper),
636653
globalfee.NewAppModule(app.GlobalfeeKeeper),
654+
restake.NewAppModule(appCodec, &app.RestakeKeeper),
637655
)
638656

639657
// NOTE: Oracle module must occur before distr as it takes some fee to distribute to active oracle validators.
@@ -646,6 +664,7 @@ func NewBandApp(
646664
minttypes.ModuleName,
647665
oracletypes.ModuleName,
648666
feedstypes.ModuleName,
667+
restaketypes.ModuleName,
649668
distrtypes.ModuleName,
650669
slashingtypes.ModuleName,
651670
evidencetypes.ModuleName,
@@ -673,6 +692,7 @@ func NewBandApp(
673692
stakingtypes.ModuleName,
674693
oracletypes.ModuleName,
675694
feedstypes.ModuleName,
695+
restaketypes.ModuleName,
676696
ibctransfertypes.ModuleName,
677697
ibcexported.ModuleName,
678698
icatypes.ModuleName,
@@ -725,6 +745,7 @@ func NewBandApp(
725745
oracletypes.ModuleName,
726746
feedstypes.ModuleName,
727747
globalfeetypes.ModuleName,
748+
restaketypes.ModuleName,
728749
)
729750

730751
app.mm.RegisterInvariants(app.CrisisKeeper)

app/genesis.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ import (
4343
globalfeetypes "github.com/bandprotocol/chain/v2/x/globalfee/types"
4444
"github.com/bandprotocol/chain/v2/x/oracle"
4545
oracletypes "github.com/bandprotocol/chain/v2/x/oracle/types"
46+
"github.com/bandprotocol/chain/v2/x/restake"
47+
restaketypes "github.com/bandprotocol/chain/v2/x/restake/types"
4648
)
4749

4850
// GenesisState defines a type alias for the Band genesis application state.
@@ -110,5 +112,6 @@ func NewDefaultGenesisState() GenesisState {
110112
oracletypes.ModuleName: oracle.AppModuleBasic{}.DefaultGenesis(cdc),
111113
feedstypes.ModuleName: feeds.AppModuleBasic{}.DefaultGenesis(cdc),
112114
globalfeetypes.ModuleName: cdc.MustMarshalJSON(globalfeeGenesis),
115+
restaketypes.ModuleName: restake.AppModuleBasic{}.DefaultGenesis(cdc),
113116
}
114117
}

app/keepers/keepers.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
feedskeeper "github.com/bandprotocol/chain/v2/x/feeds/keeper"
2525
globalfeekeeper "github.com/bandprotocol/chain/v2/x/globalfee/keeper"
2626
oraclekeeper "github.com/bandprotocol/chain/v2/x/oracle/keeper"
27+
restakekeeper "github.com/bandprotocol/chain/v2/x/restake/keeper"
2728
)
2829

2930
type AppKeepers struct {
@@ -51,6 +52,7 @@ type AppKeepers struct {
5152
FeedsKeeper feedskeeper.Keeper
5253
ConsensusParamsKeeper consensusparamkeeper.Keeper
5354
GlobalfeeKeeper globalfeekeeper.Keeper
55+
RestakeKeeper restakekeeper.Keeper
5456

5557
// make scoped keepers public for test purposes
5658
ScopedIBCKeeper capabilitykeeper.ScopedKeeper

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.22.3
44

55
require (
66
cosmossdk.io/api v0.3.1
7+
cosmossdk.io/core v0.5.1
78
cosmossdk.io/errors v1.0.1
89
cosmossdk.io/math v1.3.0
910
github.com/bandprotocol/bothan/bothan-api/client/go-client v0.0.1-alpha.1
@@ -46,7 +47,6 @@ require (
4647
cloud.google.com/go/compute/metadata v0.2.3 // indirect
4748
cloud.google.com/go/iam v1.1.6 // indirect
4849
cloud.google.com/go/storage v1.36.0 // indirect
49-
cosmossdk.io/core v0.5.1 // indirect
5050
cosmossdk.io/depinject v1.0.0-alpha.4 // indirect
5151
cosmossdk.io/log v1.3.1 // indirect
5252
cosmossdk.io/tools/rosetta v0.2.1 // indirect
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
syntax = "proto3";
2+
package restake.v1beta1;
3+
4+
option go_package = "github.com/bandprotocol/chain/v2/x/restake/types";
5+
6+
import "amino/amino.proto";
7+
import "gogoproto/gogo.proto";
8+
import "cosmos_proto/cosmos.proto";
9+
import "cosmos/base/v1beta1/coin.proto";
10+
import "restake/v1beta1/types.proto";
11+
12+
// GenesisState represents the initial state of the blockchain.
13+
message GenesisState {
14+
// Keys is a list of keys in the module.
15+
repeated Key keys = 1 [(gogoproto.nullable) = false];
16+
17+
// Stake is a list of stakes in the module.
18+
repeated Stake stakes = 2 [(gogoproto.nullable) = false];
19+
20+
// Rewards is a list of rewards in the module.
21+
repeated RewardGenesis rewards = 3 [(gogoproto.nullable) = false];
22+
}
23+
24+
// RewardGenesis message represents reward details for genesis state.
25+
message RewardGenesis {
26+
option (gogoproto.equal) = true;
27+
28+
// Address is the owner address of this reward.
29+
string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
30+
31+
// Key is the key that this rewards belongs to.
32+
string key = 2;
33+
34+
// Amounts is a list of reward amounts for this address and key.
35+
repeated cosmos.base.v1beta1.DecCoin amounts = 3 [
36+
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins",
37+
(gogoproto.nullable) = false,
38+
(amino.dont_omitempty) = true
39+
];
40+
}

proto/restake/v1beta1/query.proto

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
syntax = "proto3";
2+
package restake.v1beta1;
3+
4+
option go_package = "github.com/bandprotocol/chain/v2/x/restake/types";
5+
6+
import "gogoproto/gogo.proto";
7+
import "google/api/annotations.proto";
8+
import "cosmos/base/query/v1beta1/pagination.proto";
9+
import "restake/v1beta1/types.proto";
10+
11+
// Query service defines the gRPC querier service for restake.
12+
service Query {
13+
// Keys returns a list of keys.
14+
rpc Keys(QueryKeysRequest) returns (QueryKeysResponse) {
15+
option (google.api.http).get = "/restake/v1beta1/keys";
16+
}
17+
18+
// Key returns a key information
19+
rpc Key(QueryKeyRequest) returns (QueryKeyResponse) {
20+
option (google.api.http).get = "/restake/v1beta1/keys/{key}";
21+
}
22+
23+
// Rewards returns rewards for a specific address.
24+
rpc Rewards(QueryRewardsRequest) returns (QueryRewardsResponse) {
25+
option (google.api.http).get = "/restake/v1beta1/addresses/{address}/rewards";
26+
}
27+
28+
// Locks returns all lock information for a specific address.
29+
rpc Locks(QueryLocksRequest) returns (QueryLocksResponse) {
30+
option (google.api.http).get = "/restake/v1beta1/addresses/{address}/locks";
31+
}
32+
}
33+
34+
// QueryKeysRequest represents the request type for the Query/Keys RPC method.
35+
message QueryKeysRequest {
36+
// Pagination defines optional pagination parameters.
37+
cosmos.base.query.v1beta1.PageRequest pagination = 1;
38+
}
39+
40+
// QueryKeysResponse represents the response type for the Query/Keys RPC method.
41+
message QueryKeysResponse {
42+
// Keys is a list of keys.
43+
repeated Key keys = 1;
44+
45+
// Pagination defines pagination parameters in the response.
46+
cosmos.base.query.v1beta1.PageResponse pagination = 2;
47+
}
48+
49+
// QueryKeyRequest represents the request type for the Query/Key RPC method.
50+
message QueryKeyRequest {
51+
string key = 1;
52+
}
53+
54+
// QueryKeyResponse represents the response type for the Query/Key RPC method.
55+
message QueryKeyResponse {
56+
// Key is a key information.
57+
Key key = 1 [(gogoproto.nullable) = false];
58+
}
59+
60+
// QueryRewardsRequest represents the request type for the Query/Rewards RPC method.
61+
message QueryRewardsRequest {
62+
// Address is the target address to query rewards.
63+
string address = 1;
64+
65+
// Pagination defines optional pagination parameters.
66+
cosmos.base.query.v1beta1.PageRequest pagination = 2;
67+
}
68+
69+
// QueryRewardsResponse represents the response type for the Query/Rewards RPC method.
70+
message QueryRewardsResponse {
71+
// Rewards is a list of rewards for the address.
72+
repeated Reward rewards = 1;
73+
74+
// Pagination defines pagination parameters in the response.
75+
cosmos.base.query.v1beta1.PageResponse pagination = 2;
76+
}
77+
78+
// QueryLocksRequest represents the request type for the Query/Locks RPC method.
79+
message QueryLocksRequest {
80+
// Address is the target address to query locks.
81+
string address = 1;
82+
83+
// Pagination defines optional pagination parameters.
84+
cosmos.base.query.v1beta1.PageRequest pagination = 2;
85+
}
86+
87+
// QueryLocksResponse represents the response type for the Query/Locks RPC method.
88+
message QueryLocksResponse {
89+
// Locks is a list of locks of the address.
90+
repeated Lock locks = 1;
91+
92+
// Pagination defines pagination parameters in the response.
93+
cosmos.base.query.v1beta1.PageResponse pagination = 2;
94+
}

proto/restake/v1beta1/tx.proto

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
syntax = "proto3";
2+
package restake.v1beta1;
3+
4+
option go_package = "github.com/bandprotocol/chain/v2/x/restake/types";
5+
6+
import "amino/amino.proto";
7+
import "cosmos/base/v1beta1/coin.proto";
8+
import "cosmos/msg/v1/msg.proto";
9+
import "cosmos_proto/cosmos.proto";
10+
import "gogoproto/gogo.proto";
11+
12+
// Service definition for Msg which handles oracle related messages.
13+
service Msg {
14+
// RPC method for claiming rewards.
15+
rpc ClaimRewards(MsgClaimRewards) returns (MsgClaimRewardsResponse);
16+
17+
//////////////////////////////////////////
18+
// Methods below are for testing only.
19+
//////////////////////////////////////////
20+
21+
// RPC method for locking powers.
22+
rpc LockPower(MsgLockPower) returns (MsgLockPowerResponse);
23+
24+
// RPC method for adding rewards.
25+
rpc AddRewards(MsgAddRewards) returns (MsgAddRewardsResponse);
26+
27+
// RPC method for deactivating a key.
28+
rpc DeactivateKey(MsgDeactivateKey) returns (MsgDeactivateKeyResponse);
29+
}
30+
31+
// MsgClaimRewards is the request message type for claiming rewards.
32+
message MsgClaimRewards {
33+
option (cosmos.msg.v1.signer) = "address";
34+
option (amino.name) = "restake/MsgClaimRewards";
35+
36+
// Address is the address that will claim the rewards.
37+
string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
38+
39+
// Key is the key that want to claim rewards from.
40+
string key = 2;
41+
}
42+
43+
// MsgClaimRewardsResponse is the response message type for claiming rewards.
44+
message MsgClaimRewardsResponse {}
45+
46+
// MsgLockPower is the request message type for locking tokens.
47+
message MsgLockPower {
48+
option (cosmos.msg.v1.signer) = "address";
49+
option (amino.name) = "restake/MsgLockPower";
50+
51+
// Address is the address will be locked power.
52+
string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
53+
54+
// Key is the key of the lock.
55+
string key = 2;
56+
57+
// Amount is the locked amount.
58+
string amount = 3 [
59+
(cosmos_proto.scalar) = "cosmos.Int",
60+
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
61+
(gogoproto.nullable) = false
62+
];
63+
}
64+
65+
// MsgLockPowerResponse is the response message type for locking power.
66+
message MsgLockPowerResponse {}
67+
68+
// MsgAddRewards is the request message type for adding rewards.
69+
message MsgAddRewards {
70+
option (cosmos.msg.v1.signer) = "sender";
71+
option (amino.name) = "restake/MsgAddRewards";
72+
73+
// Sender is the address that want to send rewards.
74+
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
75+
76+
// Key is the key of pool that reward will be sent to.
77+
string key = 2;
78+
79+
// Rewards is a list of rewards that will send to module.
80+
repeated cosmos.base.v1beta1.Coin rewards = 3 [
81+
(gogoproto.nullable) = false,
82+
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
83+
(gogoproto.jsontag) = "min_deposit,omitempty"
84+
];
85+
}
86+
87+
// MsgAddRewardsResponse is the response message type for adding rewards.
88+
message MsgAddRewardsResponse {}
89+
90+
// MsgDeactivateKey is the request message type for deactivating a key.
91+
message MsgDeactivateKey {
92+
option (cosmos.msg.v1.signer) = "sender";
93+
option (amino.name) = "restake/MsgDeactivateKey";
94+
95+
// Sender is the sender of the message.
96+
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
97+
98+
// Key is the key that will be deactivated.
99+
string key = 2;
100+
}
101+
102+
// MsgDeactivateKeyResponse is the response message type for deactivating a key.
103+
message MsgDeactivateKeyResponse {}

0 commit comments

Comments
 (0)