mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-26 16:25:21 +00:00
779f8081e7
* add uatom ibc denom to money markets in hard migration * add new money market to stability committee * clean up * update v0_16 migration test data * add swp, uatom ibc denoms to hard gov committee * update committee migration testdata * update general migration test data * specify committee ID with vars * fix merge var rename bug Co-authored-by: rhuairahrighairigh <ruaridh.odonnell@gmail.com>
565 lines
18 KiB
Go
565 lines
18 KiB
Go
package v0_16
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"sort"
|
|
|
|
proto "github.com/gogo/protobuf/proto"
|
|
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
v036distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v036"
|
|
v040distr "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
|
v036gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v036"
|
|
v040gov "github.com/cosmos/cosmos-sdk/x/gov/types"
|
|
v036params "github.com/cosmos/cosmos-sdk/x/params/legacy/v036"
|
|
v040params "github.com/cosmos/cosmos-sdk/x/params/types/proposal"
|
|
v038upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/legacy/v038"
|
|
v040upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
|
|
|
v016bep3types "github.com/kava-labs/kava/x/bep3/types"
|
|
v016cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
|
v015committee "github.com/kava-labs/kava/x/committee/legacy/v0_15"
|
|
v016committee "github.com/kava-labs/kava/x/committee/types"
|
|
v016hardMigration "github.com/kava-labs/kava/x/hard/legacy/v0_16"
|
|
v016hardtypes "github.com/kava-labs/kava/x/hard/types"
|
|
v015kavadist "github.com/kava-labs/kava/x/kavadist/legacy/v0_15"
|
|
v016kavadist "github.com/kava-labs/kava/x/kavadist/types"
|
|
v015pricefeed "github.com/kava-labs/kava/x/pricefeed/legacy/v0_15"
|
|
v016pricefeedmigration "github.com/kava-labs/kava/x/pricefeed/legacy/v0_16"
|
|
v016pricefeedtypes "github.com/kava-labs/kava/x/pricefeed/types"
|
|
)
|
|
|
|
const (
|
|
KavaStabilityCommitteeID = 1
|
|
HardGovernanceCommitteeID = 3
|
|
)
|
|
|
|
// migrateWhitelist returns an string slice of json keys that should be whitelisted on the whitelist interface
|
|
func migrateWhitelist(whitelist interface{}, ignoredTag string) []string {
|
|
allowed := []string{}
|
|
v := reflect.ValueOf(whitelist)
|
|
typeOfS := v.Type()
|
|
for i := 0; i < v.NumField(); i++ {
|
|
tag := typeOfS.Field(i).Tag.Get("json")
|
|
if tag != ignoredTag && tag != "" {
|
|
val, ok := v.Field(i).Interface().(bool)
|
|
if ok && val {
|
|
allowed = append(allowed, tag)
|
|
}
|
|
}
|
|
}
|
|
sort.Strings(allowed)
|
|
return allowed
|
|
}
|
|
|
|
// isSubparamAllowed returns true if the subspace and key is allowed in the v15 permissions
|
|
func isSubparamAllowed(permission v015committee.SubParamChangePermission, subspace string, key string) bool {
|
|
for _, allowed := range permission.AllowedParams {
|
|
if allowed.Key == key && allowed.Subspace == subspace {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type subspaceKeyPair struct {
|
|
key []byte
|
|
subspace string
|
|
}
|
|
|
|
// migrateSubParamPermissions converts v15 SubParamChangePermissions to v16 ParamsChangePermission
|
|
func migrateSubParamPermissions(
|
|
permission v015committee.SubParamChangePermission,
|
|
committeeID uint64,
|
|
oldPricefeedState v015pricefeed.GenesisState,
|
|
) *v016committee.ParamsChangePermission {
|
|
changes := v016committee.AllowedParamsChanges{}
|
|
|
|
// migrate allowed params
|
|
pairsToAvoid := []subspaceKeyPair{
|
|
{key: v016cdptypes.KeyCollateralParams, subspace: v016cdptypes.ModuleName},
|
|
{key: v016cdptypes.KeyDebtParam, subspace: v016cdptypes.ModuleName},
|
|
{key: v016bep3types.KeyAssetParams, subspace: v016bep3types.ModuleName},
|
|
{key: v016pricefeedtypes.KeyMarkets, subspace: v016pricefeedtypes.ModuleName},
|
|
{key: v016hardtypes.KeyMoneyMarkets, subspace: v016hardtypes.ModuleName},
|
|
}
|
|
for _, allowed := range permission.AllowedParams {
|
|
shouldAvoid := false
|
|
for _, pair := range pairsToAvoid {
|
|
if string(pair.key) == allowed.Key && pair.subspace == allowed.Subspace {
|
|
shouldAvoid = true
|
|
break
|
|
}
|
|
}
|
|
if !shouldAvoid {
|
|
changes = append(changes, v016committee.AllowedParamsChange{
|
|
Subspace: allowed.Subspace,
|
|
Key: allowed.Key,
|
|
})
|
|
}
|
|
}
|
|
|
|
// migrate collateral params
|
|
if isSubparamAllowed(permission, v016cdptypes.ModuleName, string(v016cdptypes.KeyCollateralParams)) {
|
|
change := v016committee.AllowedParamsChange{
|
|
Key: string(v016cdptypes.KeyCollateralParams),
|
|
Subspace: string(v016cdptypes.ModuleName),
|
|
}
|
|
requirements := []v016committee.SubparamRequirement{}
|
|
for _, param := range permission.AllowedCollateralParams {
|
|
requirement := v016committee.SubparamRequirement{
|
|
Key: "type",
|
|
Val: param.Type,
|
|
AllowedSubparamAttrChanges: []string{},
|
|
}
|
|
allowed := migrateWhitelist(param, "type")
|
|
requirement.AllowedSubparamAttrChanges = allowed
|
|
requirements = append(requirements, requirement)
|
|
}
|
|
|
|
// add new requirement for stability committee
|
|
if committeeID == KavaStabilityCommitteeID {
|
|
requirement := v016committee.SubparamRequirement{
|
|
Key: "type",
|
|
Val: "swp-a",
|
|
AllowedSubparamAttrChanges: []string{
|
|
"auction_size", "check_collateralization_index_count", "debt_limit",
|
|
"keeper_reward_percentage", "stability_fee",
|
|
},
|
|
}
|
|
requirements = append(requirements, requirement)
|
|
}
|
|
|
|
change.MultiSubparamsRequirements = requirements
|
|
changes = append(changes, change)
|
|
}
|
|
|
|
// migrate debt params
|
|
if isSubparamAllowed(permission, string(v016cdptypes.ModuleName), string(v016cdptypes.KeyDebtParam)) {
|
|
change := v016committee.AllowedParamsChange{
|
|
Subspace: v016cdptypes.ModuleName,
|
|
Key: string(v016cdptypes.KeyDebtParam),
|
|
SingleSubparamAllowedAttrs: migrateWhitelist(permission.AllowedDebtParam, ""),
|
|
}
|
|
changes = append(changes, change)
|
|
}
|
|
|
|
// migrate asset params
|
|
if isSubparamAllowed(permission, string(v016bep3types.ModuleName), string(v016bep3types.KeyAssetParams)) {
|
|
change := v016committee.AllowedParamsChange{
|
|
Key: string(v016bep3types.KeyAssetParams),
|
|
Subspace: string(v016bep3types.ModuleName),
|
|
}
|
|
requirements := []v016committee.SubparamRequirement{}
|
|
for _, param := range permission.AllowedAssetParams {
|
|
requirement := v016committee.SubparamRequirement{
|
|
Key: "denom",
|
|
Val: param.Denom,
|
|
AllowedSubparamAttrChanges: []string{},
|
|
}
|
|
allowed := migrateWhitelist(param, "denom")
|
|
requirement.AllowedSubparamAttrChanges = allowed
|
|
requirements = append(requirements, requirement)
|
|
}
|
|
change.MultiSubparamsRequirements = requirements
|
|
changes = append(changes, change)
|
|
}
|
|
|
|
// migrate markets
|
|
if isSubparamAllowed(permission, string(v016pricefeedtypes.ModuleName), string(v016pricefeedtypes.KeyMarkets)) {
|
|
change := v016committee.AllowedParamsChange{
|
|
Key: string(v016pricefeedtypes.KeyMarkets),
|
|
Subspace: string(v016pricefeedtypes.ModuleName),
|
|
}
|
|
requirements := []v016committee.SubparamRequirement{}
|
|
for _, param := range permission.AllowedMarkets {
|
|
requirement := v016committee.SubparamRequirement{
|
|
Key: "market_id",
|
|
Val: param.MarketID,
|
|
AllowedSubparamAttrChanges: []string{},
|
|
}
|
|
allowed := migrateWhitelist(param, "market_id")
|
|
requirement.AllowedSubparamAttrChanges = allowed
|
|
requirements = append(requirements, requirement)
|
|
}
|
|
|
|
if committeeID == KavaStabilityCommitteeID {
|
|
// Add permissions for existing pricefeed markets that are missing in allowed_markets
|
|
outer:
|
|
for _, oldPricefeedMarket := range oldPricefeedState.Params.Markets {
|
|
// Skip if this oldPricefeedMarket already exists in requirements
|
|
for _, marketRequirement := range requirements {
|
|
if marketRequirement.Val == oldPricefeedMarket.MarketID {
|
|
continue outer
|
|
}
|
|
}
|
|
|
|
requirement := v016committee.SubparamRequirement{
|
|
Key: "market_id",
|
|
Val: oldPricefeedMarket.MarketID,
|
|
AllowedSubparamAttrChanges: []string{"active"},
|
|
}
|
|
|
|
requirements = append(requirements, requirement)
|
|
}
|
|
|
|
// Add new IBC denoms for stability committee
|
|
for _, market := range v016pricefeedmigration.NewIBCMarkets {
|
|
requirement := v016committee.SubparamRequirement{
|
|
Key: "market_id",
|
|
Val: market.MarketID,
|
|
AllowedSubparamAttrChanges: []string{"active"},
|
|
}
|
|
|
|
requirements = append(requirements, requirement)
|
|
}
|
|
}
|
|
|
|
change.MultiSubparamsRequirements = requirements
|
|
changes = append(changes, change)
|
|
}
|
|
|
|
// migrate money markets
|
|
if isSubparamAllowed(permission, string(v016hardtypes.ModuleName), string(v016hardtypes.KeyMoneyMarkets)) {
|
|
change := v016committee.AllowedParamsChange{
|
|
Key: string(v016hardtypes.KeyMoneyMarkets),
|
|
Subspace: string(v016hardtypes.ModuleName),
|
|
}
|
|
requirements := []v016committee.SubparamRequirement{}
|
|
for _, param := range permission.AllowedMoneyMarkets {
|
|
requirement := v016committee.SubparamRequirement{
|
|
Key: "denom",
|
|
Val: param.Denom,
|
|
AllowedSubparamAttrChanges: []string{},
|
|
}
|
|
allowed := migrateWhitelist(param, "denom")
|
|
requirement.AllowedSubparamAttrChanges = allowed
|
|
requirements = append(requirements, requirement)
|
|
}
|
|
|
|
// add new requirement for stability committee
|
|
if committeeID == KavaStabilityCommitteeID {
|
|
requirement := v016committee.SubparamRequirement{
|
|
Key: "denom",
|
|
Val: "swp",
|
|
AllowedSubparamAttrChanges: []string{
|
|
"borrow_limit", "interest_rate_model",
|
|
"keeper_reward_percentage", "reserve_factor",
|
|
},
|
|
}
|
|
requirements = append(requirements, requirement)
|
|
|
|
requirementAtom := v016committee.SubparamRequirement{
|
|
Key: "denom",
|
|
Val: v016hardMigration.UATOM_IBC_DENOM,
|
|
AllowedSubparamAttrChanges: []string{
|
|
"borrow_limit", "interest_rate_model",
|
|
"keeper_reward_percentage", "reserve_factor",
|
|
},
|
|
}
|
|
requirements = append(requirements, requirementAtom)
|
|
} else if committeeID == HardGovernanceCommitteeID {
|
|
// add new requirement for Hard Governance committee
|
|
requirementSwp := v016committee.SubparamRequirement{
|
|
Key: "denom",
|
|
Val: "swp",
|
|
AllowedSubparamAttrChanges: []string{
|
|
"borrow_limit", "interest_rate_model", "keeper_reward_percentage",
|
|
"reserve_factor", "spot_market_id",
|
|
},
|
|
}
|
|
requirements = append(requirements, requirementSwp)
|
|
|
|
requirementUatom := v016committee.SubparamRequirement{
|
|
Key: "denom",
|
|
Val: v016hardMigration.UATOM_IBC_DENOM,
|
|
AllowedSubparamAttrChanges: []string{
|
|
"borrow_limit", "interest_rate_model", "keeper_reward_percentage",
|
|
"reserve_factor", "spot_market_id",
|
|
},
|
|
}
|
|
requirements = append(requirements, requirementUatom)
|
|
}
|
|
|
|
change.MultiSubparamsRequirements = requirements
|
|
changes = append(changes, change)
|
|
}
|
|
|
|
return &v016committee.ParamsChangePermission{
|
|
AllowedParamsChanges: changes,
|
|
}
|
|
}
|
|
|
|
func migratePermission(
|
|
v015permission v015committee.Permission,
|
|
committeeID uint64,
|
|
oldPricefeedState v015pricefeed.GenesisState,
|
|
) *codectypes.Any {
|
|
var protoProposal proto.Message
|
|
|
|
switch v015permission := v015permission.(type) {
|
|
case v015committee.GodPermission:
|
|
{
|
|
protoProposal = &v016committee.GodPermission{}
|
|
}
|
|
case v015committee.TextPermission:
|
|
{
|
|
protoProposal = &v016committee.TextPermission{}
|
|
}
|
|
case v015committee.SoftwareUpgradePermission:
|
|
{
|
|
protoProposal = &v016committee.SoftwareUpgradePermission{}
|
|
}
|
|
case v015committee.SimpleParamChangePermission:
|
|
{
|
|
changes := make(v016committee.AllowedParamsChanges, len(v015permission.AllowedParams))
|
|
for i, param := range v015permission.AllowedParams {
|
|
changes[i] = v016committee.AllowedParamsChange{
|
|
Subspace: param.Subspace,
|
|
Key: param.Key,
|
|
}
|
|
}
|
|
protoProposal = &v016committee.ParamsChangePermission{
|
|
AllowedParamsChanges: changes,
|
|
}
|
|
}
|
|
case v015committee.SubParamChangePermission:
|
|
{
|
|
protoProposal = migrateSubParamPermissions(v015permission, committeeID, oldPricefeedState)
|
|
}
|
|
default:
|
|
panic(fmt.Errorf("'%s' is not a valid permission", v015permission))
|
|
}
|
|
|
|
// Convert the content into Any.
|
|
contentAny, err := codectypes.NewAnyWithValue(protoProposal)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return contentAny
|
|
}
|
|
|
|
func migrateTallyOption(oldTallyOption v015committee.TallyOption) v016committee.TallyOption {
|
|
switch oldTallyOption {
|
|
case v015committee.NullTallyOption:
|
|
return v016committee.TALLY_OPTION_UNSPECIFIED
|
|
case v015committee.FirstPastThePost:
|
|
return v016committee.TALLY_OPTION_FIRST_PAST_THE_POST
|
|
case v015committee.Deadline:
|
|
return v016committee.TALLY_OPTION_DEADLINE
|
|
default:
|
|
panic(fmt.Errorf("'%s' is not a valid tally option", oldTallyOption))
|
|
}
|
|
}
|
|
|
|
func migrateCommittee(committee v015committee.Committee, oldPricefeedState v015pricefeed.GenesisState) *codectypes.Any {
|
|
var protoProposal proto.Message
|
|
switch committee := committee.(type) {
|
|
case v015committee.MemberCommittee:
|
|
{
|
|
permissions := make([]*codectypes.Any, len(committee.Permissions))
|
|
for i, permission := range committee.Permissions {
|
|
permissions[i] = migratePermission(permission, committee.GetID(), oldPricefeedState)
|
|
}
|
|
|
|
protoProposal = &v016committee.MemberCommittee{
|
|
BaseCommittee: &v016committee.BaseCommittee{
|
|
ID: committee.ID,
|
|
Description: committee.Description,
|
|
Members: committee.Members,
|
|
Permissions: permissions,
|
|
VoteThreshold: committee.VoteThreshold,
|
|
ProposalDuration: committee.ProposalDuration,
|
|
TallyOption: migrateTallyOption(committee.TallyOption),
|
|
},
|
|
}
|
|
}
|
|
case v015committee.TokenCommittee:
|
|
{
|
|
permissions := make([]*codectypes.Any, len(committee.Permissions))
|
|
for i, permission := range committee.Permissions {
|
|
permissions[i] = migratePermission(permission, committee.GetID(), oldPricefeedState)
|
|
}
|
|
|
|
protoProposal = &v016committee.TokenCommittee{
|
|
BaseCommittee: &v016committee.BaseCommittee{
|
|
ID: committee.ID,
|
|
Description: committee.Description,
|
|
Members: committee.Members,
|
|
Permissions: permissions,
|
|
VoteThreshold: committee.VoteThreshold,
|
|
ProposalDuration: committee.ProposalDuration,
|
|
TallyOption: migrateTallyOption(committee.TallyOption),
|
|
},
|
|
Quorum: committee.Quorum,
|
|
TallyDenom: committee.TallyDenom,
|
|
}
|
|
}
|
|
default:
|
|
panic(fmt.Errorf("'%s' is not a valid committee", committee))
|
|
}
|
|
|
|
// Convert the content into Any.
|
|
contentAny, err := codectypes.NewAnyWithValue(protoProposal)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return contentAny
|
|
}
|
|
|
|
func migrateCommittees(v015committees v015committee.Committees, oldPricefeedState v015pricefeed.GenesisState) []*codectypes.Any {
|
|
committees := make([]*codectypes.Any, len(v015committees))
|
|
for i, committee := range v015committees {
|
|
committees[i] = migrateCommittee(committee, oldPricefeedState)
|
|
}
|
|
return committees
|
|
}
|
|
|
|
func migrateContent(oldContent v036gov.Content) *codectypes.Any {
|
|
var protoProposal proto.Message
|
|
|
|
switch oldContent := oldContent.(type) {
|
|
case v036gov.TextProposal:
|
|
{
|
|
protoProposal = &v040gov.TextProposal{
|
|
Title: oldContent.Title,
|
|
Description: oldContent.Description,
|
|
}
|
|
// Convert the content into Any.
|
|
contentAny, err := codectypes.NewAnyWithValue(protoProposal)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return contentAny
|
|
}
|
|
case v036distr.CommunityPoolSpendProposal:
|
|
{
|
|
protoProposal = &v040distr.CommunityPoolSpendProposal{
|
|
Title: oldContent.Title,
|
|
Description: oldContent.Description,
|
|
Recipient: oldContent.Recipient.String(),
|
|
Amount: oldContent.Amount,
|
|
}
|
|
}
|
|
case v038upgrade.CancelSoftwareUpgradeProposal:
|
|
{
|
|
protoProposal = &v040upgrade.CancelSoftwareUpgradeProposal{
|
|
Description: oldContent.Description,
|
|
Title: oldContent.Title,
|
|
}
|
|
}
|
|
case v038upgrade.SoftwareUpgradeProposal:
|
|
{
|
|
protoProposal = &v040upgrade.SoftwareUpgradeProposal{
|
|
Description: oldContent.Description,
|
|
Title: oldContent.Title,
|
|
Plan: v040upgrade.Plan{
|
|
Name: oldContent.Plan.Name,
|
|
Height: oldContent.Plan.Height,
|
|
Info: oldContent.Plan.Info,
|
|
},
|
|
}
|
|
}
|
|
case v036params.ParameterChangeProposal:
|
|
{
|
|
newChanges := make([]v040params.ParamChange, len(oldContent.Changes))
|
|
for i, oldChange := range oldContent.Changes {
|
|
newChanges[i] = v040params.ParamChange{
|
|
Subspace: oldChange.Subspace,
|
|
Key: oldChange.Key,
|
|
Value: oldChange.Value,
|
|
}
|
|
}
|
|
|
|
protoProposal = &v040params.ParameterChangeProposal{
|
|
Description: oldContent.Description,
|
|
Title: oldContent.Title,
|
|
Changes: newChanges,
|
|
}
|
|
}
|
|
case v015kavadist.CommunityPoolMultiSpendProposal:
|
|
{
|
|
newRecipients := make([]v016kavadist.MultiSpendRecipient, len(oldContent.RecipientList))
|
|
for i, recipient := range oldContent.RecipientList {
|
|
newRecipients[i] = v016kavadist.MultiSpendRecipient{
|
|
Address: recipient.Address.String(),
|
|
Amount: recipient.Amount,
|
|
}
|
|
}
|
|
|
|
protoProposal = &v016kavadist.CommunityPoolMultiSpendProposal{
|
|
Description: oldContent.Description,
|
|
Title: oldContent.Title,
|
|
RecipientList: newRecipients,
|
|
}
|
|
}
|
|
default:
|
|
panic(fmt.Errorf("%T is not a valid proposal content type", oldContent))
|
|
}
|
|
|
|
// Convert the content into Any.
|
|
contentAny, err := codectypes.NewAnyWithValue(protoProposal)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return contentAny
|
|
}
|
|
|
|
func migrateProposals(v015proposals []v015committee.Proposal) v016committee.Proposals {
|
|
proposals := make(v016committee.Proposals, len(v015proposals))
|
|
for i, v15proposal := range v015proposals {
|
|
proposals[i] = v016committee.Proposal{
|
|
ID: v15proposal.ID,
|
|
Content: migrateContent(v15proposal.PubProposal),
|
|
CommitteeID: v15proposal.CommitteeID,
|
|
Deadline: v15proposal.Deadline,
|
|
}
|
|
}
|
|
return proposals
|
|
}
|
|
|
|
func migrateVoteType(oldVoteType v015committee.VoteType) v016committee.VoteType {
|
|
switch oldVoteType {
|
|
case v015committee.Yes:
|
|
return v016committee.VOTE_TYPE_YES
|
|
case v015committee.No:
|
|
return v016committee.VOTE_TYPE_NO
|
|
case v015committee.Abstain:
|
|
return v016committee.VOTE_TYPE_ABSTAIN
|
|
case v015committee.NullVoteType:
|
|
return v016committee.VOTE_TYPE_UNSPECIFIED
|
|
default:
|
|
panic(fmt.Errorf("'%s' is not a valid vote type", oldVoteType))
|
|
}
|
|
}
|
|
|
|
func migrateVotes(v15votes []v015committee.Vote) []v016committee.Vote {
|
|
votes := make([]v016committee.Vote, len(v15votes))
|
|
for i, v15vote := range v15votes {
|
|
votes[i] = v016committee.Vote{
|
|
ProposalID: v15vote.ProposalID,
|
|
Voter: v15vote.Voter,
|
|
VoteType: migrateVoteType(v15vote.VoteType),
|
|
}
|
|
}
|
|
return votes
|
|
}
|
|
|
|
func Migrate(
|
|
oldState v015committee.GenesisState,
|
|
oldPricefeedState v015pricefeed.GenesisState,
|
|
) *v016committee.GenesisState {
|
|
newState := v016committee.GenesisState{
|
|
NextProposalID: oldState.NextProposalID,
|
|
Committees: migrateCommittees(oldState.Committees, oldPricefeedState),
|
|
Proposals: migrateProposals(oldState.Proposals),
|
|
Votes: migrateVotes(oldState.Votes),
|
|
}
|
|
return &newState
|
|
}
|