Skip to content

Commit

Permalink
incentive: full tokenomics implementation (#260)
Browse files Browse the repository at this point in the history
Resolves babylonlabs-io/pm#100

This PR implements the leftover issues in the tokenmomics, including

- removing BTC timestamping related incentive mechanisms
- rewarding all active FPs rather than those who voted (we can do this
because of jailing mechanism, and this is in line with Cosmos SDK)

The rest of the [tokenomics
issue](babylonlabs-io/pm#100) are mostly
parameters and benchmarking, which depend on external factors and other
engineering efforts.
  • Loading branch information
SebastianElvis authored Nov 13, 2024
1 parent d4d31e1 commit dd4009d
Show file tree
Hide file tree
Showing 46 changed files with 258 additions and 1,561 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ in checkpointing module

### State Machine Breaking

* [#260](https://github.com/babylonlabs-io/babylon/pull/260) Finish tokenomics
implementation
* [#254](https://github.com/babylonlabs-io/babylon/pull/254) Avoid constant
bech-32 decoding in power table

Expand Down
2 changes: 1 addition & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ func NewBabylonApp(
app.ModuleManager.SetOrderBeginBlockers(
upgradetypes.ModuleName, capabilitytypes.ModuleName,
// NOTE: incentive module's BeginBlock has to be after mint but before distribution
// so that it can intercept a part of new inflation to reward BTC staking/timestamping stakeholders
// so that it can intercept a part of new inflation to reward BTC staking stakeholders
minttypes.ModuleName, incentivetypes.ModuleName, distrtypes.ModuleName,
slashingtypes.ModuleName,
evidencetypes.ModuleName, stakingtypes.ModuleName,
Expand Down
1 change: 1 addition & 0 deletions app/include_upgrade_mainnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func init() {
Upgrades = []upgrades.Upgrade{v1.CreateUpgrade(v1.UpgradeDataString{
BtcStakingParamStr: mainnet.BtcStakingParamStr,
FinalityParamStr: mainnet.FinalityParamStr,
IncentiveParamStr: mainnet.IncentiveParamStr,
CosmWasmParamStr: mainnet.CosmWasmParamStr,
NewBtcHeadersStr: mainnet.NewBtcHeadersStr,
TokensDistributionStr: mainnet.TokensDistributionStr,
Expand Down
1 change: 1 addition & 0 deletions app/include_upgrade_testnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func init() {
Upgrades = []upgrades.Upgrade{v1.CreateUpgrade(v1.UpgradeDataString{
BtcStakingParamStr: testnet.BtcStakingParamStr,
FinalityParamStr: testnet.FinalityParamStr,
IncentiveParamStr: testnet.IncentiveParamStr,
CosmWasmParamStr: testnet.CosmWasmParamStr,
NewBtcHeadersStr: testnet.NewBtcHeadersStr,
TokensDistributionStr: testnet.TokensDistributionStr,
Expand Down
5 changes: 5 additions & 0 deletions app/upgrades/v1/mainnet/incentive.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package mainnet

const IncentiveParamStr = `{
"btc_staking_portion": "0.6"
}`
5 changes: 5 additions & 0 deletions app/upgrades/v1/testnet/incentive.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package testnet

const IncentiveParamStr = `{
"btc_staking_portion": "0.6"
}`
1 change: 1 addition & 0 deletions app/upgrades/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package v1
type UpgradeDataString struct {
BtcStakingParamStr string
FinalityParamStr string
IncentiveParamStr string
CosmWasmParamStr string
NewBtcHeadersStr string
TokensDistributionStr string
Expand Down
36 changes: 35 additions & 1 deletion app/upgrades/v1/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import (
btcstktypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"
finalitykeeper "github.com/babylonlabs-io/babylon/x/finality/keeper"
finalitytypes "github.com/babylonlabs-io/babylon/x/finality/types"
incentivekeeper "github.com/babylonlabs-io/babylon/x/incentive/keeper"
incentivetypes "github.com/babylonlabs-io/babylon/x/incentive/types"
mintkeeper "github.com/babylonlabs-io/babylon/x/mint/keeper"
minttypes "github.com/babylonlabs-io/babylon/x/mint/types"
)
Expand Down Expand Up @@ -82,9 +84,11 @@ func CreateUpgradeHandler(upgradeDataStr UpgradeDataString) upgrades.UpgradeHand
keepers.EncCfg.Codec,
&keepers.BTCStakingKeeper,
&keepers.FinalityKeeper,
&keepers.IncentiveKeeper,
&keepers.WasmKeeper,
upgradeDataStr.BtcStakingParamStr,
upgradeDataStr.FinalityParamStr,
upgradeDataStr.IncentiveParamStr,
upgradeDataStr.CosmWasmParamStr,
)
if err != nil {
Expand Down Expand Up @@ -130,8 +134,9 @@ func upgradeParameters(
cdc codec.Codec,
btcK *btcstkkeeper.Keeper,
finK *finalitykeeper.Keeper,
iK *incentivekeeper.Keeper,
wasmK *wasmkeeper.Keeper,
btcStakingParam, finalityParam, wasmParam string,
btcStakingParam, finalityParam, incentiveParam, wasmParam string,
) error {
// Upgrade the staking parameters as first, as other upgrades depend on it.
if err := upgradeBtcStakingParameters(ctx, cdc, btcK, btcStakingParam); err != nil {
Expand All @@ -140,10 +145,27 @@ func upgradeParameters(
if err := upgradeFinalityParameters(ctx, cdc, finK, finalityParam); err != nil {
return err
}
if err := upgradeIncentiveParameters(ctx, cdc, iK, incentiveParam); err != nil {
return err
}

return upgradeCosmWasmParameters(ctx, cdc, wasmK, wasmParam)
}

func upgradeIncentiveParameters(
ctx sdk.Context,
cdc codec.Codec,
k *incentivekeeper.Keeper,
incentiveParam string,
) error {
params, err := LoadIncentiveParamsFromData(cdc, incentiveParam)
if err != nil {
return err
}

return k.SetParams(ctx, params)
}

func upgradeCosmWasmParameters(
ctx sdk.Context,
cdc codec.Codec,
Expand Down Expand Up @@ -264,6 +286,18 @@ func LoadFinalityParamsFromData(cdc codec.Codec, data string) (finalitytypes.Par
return params, nil
}

func LoadIncentiveParamsFromData(cdc codec.Codec, data string) (incentivetypes.Params, error) {
buff := bytes.NewBufferString(data)

var params incentivetypes.Params
err := cdc.UnmarshalJSON(buff.Bytes(), &params)
if err != nil {
return incentivetypes.Params{}, err
}

return params, nil
}

func LoadCosmWasmParamsFromData(cdc codec.Codec, data string) (wasmtypes.Params, error) {
buff := bytes.NewBufferString(data)

Expand Down
8 changes: 8 additions & 0 deletions app/upgrades/v1/upgrades_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ var (
UpgradeV1DataTestnet = v1.UpgradeDataString{
BtcStakingParamStr: testnetdata.BtcStakingParamStr,
FinalityParamStr: testnetdata.FinalityParamStr,
IncentiveParamStr: testnetdata.IncentiveParamStr,
CosmWasmParamStr: testnetdata.CosmWasmParamStr,
NewBtcHeadersStr: testnetdata.NewBtcHeadersStr,
TokensDistributionStr: testnetdata.TokensDistributionStr,
}
UpgradeV1DataMainnet = v1.UpgradeDataString{
BtcStakingParamStr: mainnetdata.BtcStakingParamStr,
FinalityParamStr: mainnetdata.FinalityParamStr,
IncentiveParamStr: mainnetdata.IncentiveParamStr,
CosmWasmParamStr: mainnetdata.CosmWasmParamStr,
NewBtcHeadersStr: mainnetdata.NewBtcHeadersStr,
TokensDistributionStr: mainnetdata.TokensDistributionStr,
Expand Down Expand Up @@ -258,6 +260,12 @@ func (s *UpgradeTestSuite) PostUpgrade() {
newHeadersLen := len(allBtcHeaders)
s.Equal(newHeadersLen, s.btcHeadersLenPreUpgrade+lenHeadersInserted)

// ensure the incentive params were set as expected
incentiveParamsFromUpgrade, err := v1.LoadIncentiveParamsFromData(s.app.AppCodec(), s.upgradeDataStr.IncentiveParamStr)
s.NoError(err)
incentiveParams := s.app.IncentiveKeeper.GetParams(s.ctx)
s.EqualValues(incentiveParamsFromUpgrade, incentiveParams)

// ensure the headers were inserted as expected
for i, btcHeaderInserted := range btcHeadersInserted {
btcHeaderInState := allBtcHeaders[s.btcHeadersLenPreUpgrade+i]
Expand Down
4 changes: 2 additions & 2 deletions proto/babylon/finality/v1/finality.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import "google/protobuf/timestamp.proto";
// and their BTC delegations at a height
message VotingPowerDistCache {
option (gogoproto.goproto_getters) = false;
// total_sat is the total amount of bonded BTC stake (in Satoshi) of all the finality providers
// total_voting_power is the total voting power of all (active) finality providers
// in the cache
uint64 total_bonded_sat = 1;
uint64 total_voting_power = 1;
// finality_providers is a list of finality providers' voting power information
repeated FinalityProviderDistInfo finality_providers = 2;
// num_active_fps is the number of finality providers that have active BTC
Expand Down
2 changes: 1 addition & 1 deletion proto/babylon/incentive/incentive.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ message Gauge {
];
}

// RewardGauge is an object that stores rewards distributed to a BTC staking/timestamping stakeholder
// RewardGauge is an object that stores rewards distributed to a BTC staking stakeholder
// code adapted from https://github.com/osmosis-labs/osmosis/blob/v18.0.0/proto/osmosis/incentives/gauge.proto
message RewardGauge {
// coins are coins that have been in the gauge
Expand Down
14 changes: 1 addition & 13 deletions proto/babylon/incentive/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,10 @@ option go_package = "github.com/babylonlabs-io/babylon/x/incentive/types";
message Params {
option (gogoproto.goproto_stringer) = false;

// submitter_portion is the portion of rewards that goes to submitter
string submitter_portion = 1 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
// reporter_portion is the portion of rewards that goes to reporter
string reporter_portion = 2 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
// btc_staking_portion is the portion of rewards that goes to Finality Providers/delegations
// NOTE: the portion of each Finality Provider/delegation is calculated by using its voting
// power and finality provider's commission
string btc_staking_portion = 3 [
string btc_staking_portion = 1 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
Expand Down
29 changes: 2 additions & 27 deletions proto/babylon/incentive/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ service Query {
rpc BTCStakingGauge(QueryBTCStakingGaugeRequest) returns (QueryBTCStakingGaugeResponse) {
option (google.api.http).get = "/babylon/incentive/btc_staking_gauge/{height}";
}
// BTCTimestampingGauge queries the BTC timestamping gauge of a given epoch
rpc BTCTimestampingGauge(QueryBTCTimestampingGaugeRequest) returns (QueryBTCTimestampingGaugeResponse) {
option (google.api.http).get = "/babylon/incentive/btc_timestamping_gauge/{epoch_num}";
}
}

// QueryParamsRequest is request type for the Query/Params RPC method.
Expand All @@ -44,7 +40,7 @@ message QueryRewardGaugesRequest {
string address = 1;
}

// RewardGaugesResponse is an object that stores rewards distributed to a BTC staking/timestamping stakeholder
// RewardGaugesResponse is an object that stores rewards distributed to a BTC staking stakeholder
message RewardGaugesResponse {
// coins are coins that have been in the gauge
// Can have multiple coin denoms
Expand Down Expand Up @@ -72,6 +68,7 @@ message QueryBTCStakingGaugeRequest {
uint64 height = 1;
}

// BTCStakingGaugeResponse is response type for the Query/BTCStakingGauge RPC method.
message BTCStakingGaugeResponse {
// coins that have been in the gauge
// can have multiple coin denoms
Expand All @@ -82,30 +79,8 @@ message BTCStakingGaugeResponse {

}

message BTCTimestampingGaugeResponse {
// coins that have been in the gauge
// can have multiple coin denoms
repeated cosmos.base.v1beta1.Coin coins = 1 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];

}

// QueryBTCStakingGaugeResponse is response type for the Query/BTCStakingGauge RPC method.
message QueryBTCStakingGaugeResponse {
// gauge is the BTC staking gauge at the queried height
BTCStakingGaugeResponse gauge = 1;
}

// QueryBTCTimestampingGaugeRequest is request type for the Query/BTCTimestampingGauge RPC method.
message QueryBTCTimestampingGaugeRequest {
// epoch_num is the queried epoch number
uint64 epoch_num = 1;
}

// QueryBTCTimestampingGaugeResponse is response type for the Query/BTCTimestampingGauge RPC method.
message QueryBTCTimestampingGaugeResponse {
// gauge is the BTC timestamping gauge at the queried epoch
BTCTimestampingGaugeResponse gauge = 1;
}
2 changes: 1 addition & 1 deletion proto/babylon/incentive/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ service Msg {
// MsgWithdrawReward defines a message for withdrawing reward of a stakeholder.
message MsgWithdrawReward {
option (cosmos.msg.v1.signer) = "address";
// {submitter, reporter, finality_provider, btc_delegation}
// {finality_provider, btc_delegation}
string type = 1;
// address is the address of the stakeholder in bech32 string
// signer of this msg has to be this address
Expand Down
Loading

0 comments on commit dd4009d

Please sign in to comment.