diff --git a/.changelog/unreleased/features/2290-add-memo-to-ICS-rewards.md b/.changelog/unreleased/features/2290-add-memo-to-ICS-rewards.md new file mode 100644 index 0000000000..421967ddab --- /dev/null +++ b/.changelog/unreleased/features/2290-add-memo-to-ICS-rewards.md @@ -0,0 +1,4 @@ +- `[x/consumer]` Populate the memo on the IBC transfer packets used to send ICS rewards. +with the required consumer chain Id to identify the consumer to the provider. +- `[x/provider]` Identify the source of ICS rewards from the IBC transfer packet memo. + ([\#2290](https://github.com/cosmos/interchain-security/pull/2290)) \ No newline at end of file diff --git a/.changelog/unreleased/state-breaking/2290-add-memo-to-ICS-rewards.md b/.changelog/unreleased/state-breaking/2290-add-memo-to-ICS-rewards.md new file mode 100644 index 0000000000..421967ddab --- /dev/null +++ b/.changelog/unreleased/state-breaking/2290-add-memo-to-ICS-rewards.md @@ -0,0 +1,4 @@ +- `[x/consumer]` Populate the memo on the IBC transfer packets used to send ICS rewards. +with the required consumer chain Id to identify the consumer to the provider. +- `[x/provider]` Identify the source of ICS rewards from the IBC transfer packet memo. + ([\#2290](https://github.com/cosmos/interchain-security/pull/2290)) \ No newline at end of file diff --git a/UPGRADING.md b/UPGRADING.md index 235010079d..c5e7375810 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -2,6 +2,28 @@ This guide provides instructions for upgrading to specific versions of Replicated Security. +## [v4.5.x](https://github.com/cosmos/interchain-security/releases/tag/v4.5.0) + +### Consumer + +Upgrading a consumer from v4.4.x to v4.5.x requires state migrations. The following migrators should be added to the upgrade handler of the consumer chain: + + +```go +// InitializeConsumerId sets the consumer Id parameter in the consumer module, +// to the consumer id for which the consumer is registered on the provider chain. +// The consumer id can be obtained in by querying the provider, e.g. by using the +// QueryConsumerIdFromClientId query. +func InitializeConsumerId(ctx sdk.Context, consumerKeeper consumerkeeper.Keeper) error { + params, err := consumerKeeper.GetConsumerParams(ctx) + if err != nil { + return err + } + params.ConsumerId = ConsumerId + return consumerKeeper.SetParams(ctx, params) +} +``` + ## [v4.4.x](https://github.com/cosmos/interchain-security/releases/tag/v4.4.0) ### Provider diff --git a/proto/interchain_security/ccv/v1/shared_consumer.proto b/proto/interchain_security/ccv/v1/shared_consumer.proto index 6c8cccfe86..36e189e1c0 100644 --- a/proto/interchain_security/ccv/v1/shared_consumer.proto +++ b/proto/interchain_security/ccv/v1/shared_consumer.proto @@ -76,6 +76,10 @@ message ConsumerParams { // The period after which a consumer can retry sending a throttled packet. google.protobuf.Duration retry_delay_period = 13 [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + + // The consumer ID of this consumer chain. Used by the consumer module to send + // ICS rewards. + string consumer_id = 14; } // ConsumerGenesisState defines shared genesis information between provider and diff --git a/tests/mbt/driver/setup.go b/tests/mbt/driver/setup.go index 9bf6459bf9..5cd4bfa121 100644 --- a/tests/mbt/driver/setup.go +++ b/tests/mbt/driver/setup.go @@ -491,6 +491,7 @@ func createConsumerGenesis(modelParams ModelParams, providerChain *ibctesting.Te []string{}, []string{}, ccvtypes.DefaultRetryDelayPeriod, + "", ) return consumertypes.NewInitialGenesisState(consumerClientState, providerConsState, valUpdates, params) diff --git a/x/ccv/consumer/keeper/distribution.go b/x/ccv/consumer/keeper/distribution.go index 3cc5b69111..8ec85ef22f 100644 --- a/x/ccv/consumer/keeper/distribution.go +++ b/x/ccv/consumer/keeper/distribution.go @@ -117,6 +117,10 @@ func (k Keeper) SendRewardsToProvider(ctx sdk.Context) error { sentCoins := sdk.NewCoins() var allBalances sdk.Coins + rewardMemo, err := ccv.CreateTransferMemo(k.GetConsumerId(ctx), ctx.ChainID()) + if err != nil { + return err + } // iterate over all whitelisted reward denoms for _, denom := range k.AllowedRewardDenoms(ctx) { // get the balance of the denom in the toSendToProviderTokens address @@ -133,7 +137,7 @@ func (k Keeper) SendRewardsToProvider(ctx sdk.Context) error { Receiver: providerAddr, // provider fee pool address to send to TimeoutHeight: timeoutHeight, // timeout height disabled TimeoutTimestamp: timeoutTimestamp, - Memo: "consumer chain rewards distribution", + Memo: rewardMemo, } // validate MsgTransfer before calling Transfer() diff --git a/x/ccv/consumer/keeper/params.go b/x/ccv/consumer/keeper/params.go index 8d74205b8a..cfc48a31f1 100644 --- a/x/ccv/consumer/keeper/params.go +++ b/x/ccv/consumer/keeper/params.go @@ -25,6 +25,7 @@ func (k Keeper) GetConsumerParams(ctx sdk.Context) ccvtypes.ConsumerParams { k.GetRewardDenoms(ctx), k.GetProviderRewardDenoms(ctx), k.GetRetryDelayPeriod(ctx), + k.GetConsumerId(ctx), ) } @@ -136,3 +137,9 @@ func (k Keeper) GetRetryDelayPeriod(ctx sdk.Context) time.Duration { k.paramStore.Get(ctx, ccvtypes.KeyRetryDelayPeriod, &period) return period } + +func (k Keeper) GetConsumerId(ctx sdk.Context) string { + var cId string + k.paramStore.Get(ctx, ccvtypes.KeyConsumerId, &cId) + return cId +} diff --git a/x/ccv/consumer/keeper/params_test.go b/x/ccv/consumer/keeper/params_test.go index 536ae98236..801f96478d 100644 --- a/x/ccv/consumer/keeper/params_test.go +++ b/x/ccv/consumer/keeper/params_test.go @@ -31,6 +31,7 @@ func TestParams(t *testing.T) { rewardDenoms, provideRewardDenoms, ccv.DefaultRetryDelayPeriod, + "0", ) // these are the default params, IBC suite independently sets enabled=true params := consumerKeeper.GetConsumerParams(ctx) @@ -38,7 +39,7 @@ func TestParams(t *testing.T) { newParams := ccv.NewParams(false, 1000, "channel-2", "cosmos19pe9pg5dv9k5fzgzmsrgnw9rl9asf7ddwhu7lm", - 7*24*time.Hour, 25*time.Hour, "0.5", 500, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour) + 7*24*time.Hour, 25*time.Hour, "0.5", 500, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour, "1") consumerKeeper.SetParams(ctx, newParams) params = consumerKeeper.GetConsumerParams(ctx) require.Equal(t, newParams, params) diff --git a/x/ccv/consumer/types/genesis_test.go b/x/ccv/consumer/types/genesis_test.go index c8c61776ec..7e62574b3b 100644 --- a/x/ccv/consumer/types/genesis_test.go +++ b/x/ccv/consumer/types/genesis_test.go @@ -233,6 +233,7 @@ func TestValidateInitialGenesisState(t *testing.T) { []string{}, []string{}, ccv.DefaultRetryDelayPeriod, + "1", )), true, }, @@ -252,6 +253,7 @@ func TestValidateInitialGenesisState(t *testing.T) { []string{}, []string{}, ccv.DefaultRetryDelayPeriod, + "1", )), true, }, @@ -457,6 +459,7 @@ func TestValidateRestartConsumerGenesisState(t *testing.T) { []string{}, []string{}, ccv.DefaultRetryDelayPeriod, + "1", )), true, }, diff --git a/x/ccv/consumer/types/params_test.go b/x/ccv/consumer/types/params_test.go index 8e81e2301c..e76422266d 100644 --- a/x/ccv/consumer/types/params_test.go +++ b/x/ccv/consumer/types/params_test.go @@ -11,6 +11,8 @@ import ( // Tests the validation of consumer params that happens at genesis func TestValidateParams(t *testing.T) { + consumerId := "13" + testCases := []struct { name string params ccvtypes.ConsumerParams @@ -19,59 +21,67 @@ func TestValidateParams(t *testing.T) { {"default params", ccvtypes.DefaultParams(), true}, { "custom valid params", - ccvtypes.NewParams(true, 5, "", "", 1004, 1005, "0.5", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour), true, + ccvtypes.NewParams(true, 5, "", "", 1004, 1005, "0.5", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour, consumerId), true, }, { "custom invalid params, block per dist transmission", - ccvtypes.NewParams(true, -5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour), false, + ccvtypes.NewParams(true, -5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour, consumerId), false, }, { "custom invalid params, dist transmission channel", - ccvtypes.NewParams(true, 5, "badchannel/", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour), false, + ccvtypes.NewParams(true, 5, "badchannel/", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour, consumerId), false, }, { "custom invalid params, ccv timeout", - ccvtypes.NewParams(true, 5, "", "", -5, 1005, "0.5", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour), false, + ccvtypes.NewParams(true, 5, "", "", -5, 1005, "0.5", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour, consumerId), false, }, { "custom invalid params, transfer timeout", - ccvtypes.NewParams(true, 5, "", "", 1004, -7, "0.5", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour), false, + ccvtypes.NewParams(true, 5, "", "", 1004, -7, "0.5", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour, consumerId), false, }, { "custom invalid params, consumer redist fraction is negative", - ccvtypes.NewParams(true, 5, "", "", 5, 1005, "-0.5", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "-0.5", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour, consumerId), false, }, { "custom invalid params, consumer redist fraction is over 1", - ccvtypes.NewParams(true, 5, "", "", 5, 1005, "1.2", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "1.2", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour, consumerId), false, }, { "custom invalid params, bad consumer redist fraction ", - ccvtypes.NewParams(true, 5, "", "", 5, 1005, "notFrac", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "notFrac", 1000, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour, consumerId), false, }, { "custom invalid params, negative num historical entries", - ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", -100, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", -100, 24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour, consumerId), false, }, { "custom invalid params, negative unbonding period", - ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, -24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, -24*21*time.Hour, []string{"untrn"}, []string{"uatom"}, 2*time.Hour, consumerId), false, }, { "custom invalid params, invalid reward denom", - ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{"u"}, []string{}, 2*time.Hour), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{"u"}, []string{}, 2*time.Hour, consumerId), false, }, { "custom invalid params, invalid provider reward denom", - ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{}, []string{"a"}, 2*time.Hour), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{}, []string{"a"}, 2*time.Hour, consumerId), false, }, { "custom invalid params, retry delay period is negative", - ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{}, []string{}, -2*time.Hour), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{}, []string{}, -2*time.Hour, consumerId), false, }, { "custom invalid params, retry delay period is zero", - ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{}, []string{}, 0), false, + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{}, []string{}, 0, consumerId), false, + }, + { + "custom invalid params, consumer ID is blank", + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{}, []string{}, time.Hour, ""), false, + }, + { + "custom invalid params, consumer ID is not a uint64", + ccvtypes.NewParams(true, 5, "", "", 5, 1005, "0.5", 1000, 24*21*time.Hour, []string{}, []string{}, time.Hour, "consumerId"), false, }, } diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index d403af536e..29df3f3d57 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -358,6 +358,7 @@ func (k Keeper) MakeConsumerGenesis( []string{}, []string{}, ccv.DefaultRetryDelayPeriod, + "0", ) gen = *ccv.NewInitialConsumerGenesisState( diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 18257a508a..1f87b6e509 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -880,7 +880,8 @@ func TestMakeConsumerGenesis(t *testing.T) { "soft_opt_out_threshold": "0", "reward_denoms": [], "provider_reward_denoms": [], - "retry_delay_period": 3600000000000 + "retry_delay_period": 3600000000000, + "consumer_id": "0" }, "new_chain": true, "provider" : { diff --git a/x/ccv/types/errors.go b/x/ccv/types/errors.go index e492984e48..2cc65e484c 100644 --- a/x/ccv/types/errors.go +++ b/x/ccv/types/errors.go @@ -22,4 +22,7 @@ var ( ErrDuplicateConsumerChain = errorsmod.Register(ModuleName, 14, "consumer chain already exists") ErrConsumerChainNotFound = errorsmod.Register(ModuleName, 15, "consumer chain not found") ErrInvalidDoubleVotingEvidence = errorsmod.Register(ModuleName, 16, "invalid consumer double voting evidence") + ErrStoreKeyNotFound = errorsmod.Register(ModuleName, 17, "store key not found") + ErrStoreUnmarshal = errorsmod.Register(ModuleName, 18, "cannot unmarshal value from store") + ErrInvalidConsumerId = errorsmod.Register(ModuleName, 19, "invalid consumer id") ) diff --git a/x/ccv/types/params.go b/x/ccv/types/params.go index 5759ce28f9..4251a991bc 100644 --- a/x/ccv/types/params.go +++ b/x/ccv/types/params.go @@ -54,6 +54,7 @@ var ( KeyRewardDenoms = []byte("RewardDenoms") KeyProviderRewardDenoms = []byte("ProviderRewardDenoms") KeyRetryDelayPeriod = []byte("RetryDelayPeriod") + KeyConsumerId = []byte("ConsumerId") ) // ParamKeyTable type declaration for parameters @@ -68,6 +69,7 @@ func NewParams(enabled bool, blocksPerDistributionTransmission int64, consumerRedistributionFraction string, historicalEntries int64, consumerUnbondingPeriod time.Duration, rewardDenoms, providerRewardDenoms []string, retryDelayPeriod time.Duration, + consumerId string, ) ConsumerParams { return ConsumerParams{ Enabled: enabled, @@ -84,6 +86,7 @@ func NewParams(enabled bool, blocksPerDistributionTransmission int64, RewardDenoms: rewardDenoms, ProviderRewardDenoms: providerRewardDenoms, RetryDelayPeriod: retryDelayPeriod, + ConsumerId: consumerId, } } @@ -104,6 +107,7 @@ func DefaultParams() ConsumerParams { rewardDenoms, provideRewardDenoms, DefaultRetryDelayPeriod, + "0", ) } @@ -145,6 +149,9 @@ func (p ConsumerParams) Validate() error { if err := ValidateDuration(p.RetryDelayPeriod); err != nil { return err } + if err := ValidateConsumerId(p.ConsumerId); err != nil { + return err + } return nil } @@ -174,6 +181,8 @@ func (p *ConsumerParams) ParamSetPairs() paramtypes.ParamSetPairs { p.ProviderRewardDenoms, ValidateDenoms), paramtypes.NewParamSetPair(KeyRetryDelayPeriod, p.RetryDelayPeriod, ValidateDuration), + paramtypes.NewParamSetPair(KeyConsumerId, + p.ConsumerId, ValidateConsumerId), } } diff --git a/x/ccv/types/shared_consumer.pb.go b/x/ccv/types/shared_consumer.pb.go index 92d7105d41..b41a3287b6 100644 --- a/x/ccv/types/shared_consumer.pb.go +++ b/x/ccv/types/shared_consumer.pb.go @@ -75,6 +75,9 @@ type ConsumerParams struct { ProviderRewardDenoms []string `protobuf:"bytes,12,rep,name=provider_reward_denoms,json=providerRewardDenoms,proto3" json:"provider_reward_denoms,omitempty"` // The period after which a consumer can retry sending a throttled packet. RetryDelayPeriod time.Duration `protobuf:"bytes,13,opt,name=retry_delay_period,json=retryDelayPeriod,proto3,stdduration" json:"retry_delay_period"` + // The consumer ID of this consumer chain. Used by the consumer module to send + // ICS rewards. + ConsumerId string `protobuf:"bytes,14,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` } func (m *ConsumerParams) Reset() { *m = ConsumerParams{} } @@ -202,6 +205,13 @@ func (m *ConsumerParams) GetRetryDelayPeriod() time.Duration { return 0 } +func (m *ConsumerParams) GetConsumerId() string { + if m != nil { + return m.ConsumerId + } + return "" +} + // ConsumerGenesisState defines shared genesis information between provider and // consumer type ConsumerGenesisState struct { @@ -341,59 +351,59 @@ func init() { } var fileDescriptor_d0a8be0efc64dfbc = []byte{ - // 817 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0x41, 0x6f, 0xe4, 0x34, - 0x14, 0x6e, 0x3a, 0x4b, 0x77, 0xea, 0x69, 0xb7, 0x8b, 0x29, 0x4b, 0xe8, 0x4a, 0xd3, 0x6c, 0xe1, - 0x30, 0x02, 0x6d, 0x42, 0x4b, 0x25, 0x24, 0x6e, 0xb4, 0x65, 0x59, 0xf6, 0xd0, 0xce, 0xa6, 0x65, - 0x91, 0xe0, 0x60, 0x39, 0xf6, 0x9b, 0x89, 0x45, 0x62, 0x47, 0xb6, 0x93, 0xd2, 0x5f, 0xc0, 0x95, - 0x23, 0x3f, 0x69, 0xb9, 0xed, 0x91, 0x13, 0xa0, 0xf6, 0x8f, 0xa0, 0x38, 0x49, 0x9b, 0x41, 0x14, - 0xca, 0xcd, 0xcf, 0xef, 0xfb, 0xbe, 0xe4, 0x7b, 0xf6, 0x7b, 0x46, 0x9f, 0x08, 0x69, 0x41, 0xb3, - 0x94, 0x0a, 0x49, 0x0c, 0xb0, 0x52, 0x0b, 0x7b, 0x11, 0x31, 0x56, 0x45, 0xd5, 0x6e, 0x64, 0x52, - 0xaa, 0x81, 0x13, 0xa6, 0xa4, 0x29, 0x73, 0xd0, 0x61, 0xa1, 0x95, 0x55, 0x78, 0xeb, 0x1f, 0x18, - 0x21, 0x63, 0x55, 0x58, 0xed, 0x6e, 0x3d, 0xb6, 0x20, 0x39, 0xe8, 0x5c, 0x48, 0x1b, 0xd1, 0x84, - 0x89, 0xc8, 0x5e, 0x14, 0x60, 0x1a, 0xe2, 0x56, 0x24, 0x12, 0x16, 0x65, 0x62, 0x9e, 0x5a, 0x96, - 0x09, 0x90, 0xd6, 0x44, 0x3d, 0x74, 0xb5, 0xdb, 0x8b, 0x5a, 0xc2, 0x78, 0xae, 0xd4, 0x3c, 0x83, - 0xc8, 0x45, 0x49, 0x39, 0x8b, 0x78, 0xa9, 0xa9, 0x15, 0x4a, 0xb6, 0xf9, 0xcd, 0xb9, 0x9a, 0x2b, - 0xb7, 0x8c, 0xea, 0x55, 0xb3, 0xbb, 0x73, 0xb5, 0x82, 0x1e, 0x1c, 0xb6, 0xbf, 0x3c, 0xa5, 0x9a, - 0xe6, 0x06, 0xfb, 0xe8, 0x3e, 0x48, 0x9a, 0x64, 0xc0, 0x7d, 0x2f, 0xf0, 0x26, 0xc3, 0xb8, 0x0b, - 0xf1, 0x09, 0xfa, 0x30, 0xc9, 0x14, 0xfb, 0xc1, 0x90, 0x02, 0x34, 0xe1, 0xc2, 0x58, 0x2d, 0x92, - 0xb2, 0xfe, 0x06, 0xb1, 0x9a, 0x4a, 0x93, 0x0b, 0x63, 0x84, 0x92, 0xfe, 0x72, 0xe0, 0x4d, 0x06, - 0xf1, 0x93, 0x06, 0x3b, 0x05, 0x7d, 0xd4, 0x43, 0x9e, 0xf5, 0x80, 0xf8, 0x05, 0x7a, 0x72, 0xab, - 0x0a, 0x61, 0x29, 0x95, 0x12, 0x32, 0x7f, 0x10, 0x78, 0x93, 0xd5, 0x78, 0x9b, 0xdf, 0x22, 0x72, - 0xd8, 0xc0, 0xf0, 0xe7, 0x68, 0xab, 0xd0, 0xaa, 0x12, 0x1c, 0x34, 0x99, 0x01, 0x90, 0x42, 0xa9, - 0x8c, 0x50, 0xce, 0x35, 0x31, 0x56, 0xfb, 0xf7, 0x9c, 0xc8, 0xa3, 0x0e, 0xf1, 0x0c, 0x60, 0xaa, - 0x54, 0xf6, 0x05, 0xe7, 0xfa, 0xd4, 0x6a, 0xfc, 0x12, 0x61, 0xc6, 0x2a, 0x62, 0x45, 0x0e, 0xaa, - 0xb4, 0xb5, 0x3b, 0xa1, 0xb8, 0xff, 0x56, 0xe0, 0x4d, 0x46, 0x7b, 0xef, 0x87, 0x4d, 0x61, 0xc3, - 0xae, 0xb0, 0xe1, 0x51, 0x5b, 0xd8, 0x83, 0xe1, 0xeb, 0xdf, 0xb7, 0x97, 0x7e, 0xf9, 0x63, 0xdb, - 0x8b, 0x1f, 0x32, 0x56, 0x9d, 0x35, 0xec, 0xa9, 0x23, 0xe3, 0xef, 0xd1, 0x7b, 0xce, 0xcd, 0x0c, - 0xf4, 0xdf, 0x75, 0x57, 0xee, 0xae, 0xfb, 0x6e, 0xa7, 0xb1, 0x28, 0xfe, 0x1c, 0x05, 0xdd, 0x3d, - 0x23, 0x1a, 0x16, 0x4a, 0x38, 0xd3, 0x94, 0xd5, 0x0b, 0xff, 0xbe, 0x73, 0x3c, 0xee, 0x70, 0xf1, - 0x02, 0xec, 0x59, 0x8b, 0xc2, 0x4f, 0x11, 0x4e, 0x85, 0xb1, 0x4a, 0x0b, 0x46, 0x33, 0x02, 0xd2, - 0x6a, 0x01, 0xc6, 0x1f, 0xba, 0x03, 0x7c, 0xfb, 0x26, 0xf3, 0x65, 0x93, 0xc0, 0xc7, 0xe8, 0x61, - 0x29, 0x13, 0x25, 0xb9, 0x90, 0xf3, 0xce, 0xce, 0xea, 0xdd, 0xed, 0x6c, 0x5c, 0x93, 0x5b, 0x23, - 0x9f, 0xa1, 0x47, 0x46, 0xcd, 0x2c, 0x51, 0x85, 0x25, 0x75, 0x85, 0x6c, 0xaa, 0xc1, 0xa4, 0x2a, - 0xe3, 0x3e, 0xaa, 0x7f, 0xff, 0x60, 0xd9, 0xf7, 0xe2, 0x77, 0x6a, 0xc4, 0x49, 0x61, 0x4f, 0x4a, - 0x7b, 0xd6, 0xa5, 0xf1, 0x07, 0x68, 0x5d, 0xc3, 0x39, 0xd5, 0x9c, 0x70, 0x90, 0x2a, 0x37, 0xfe, - 0x28, 0x18, 0x4c, 0x56, 0xe3, 0xb5, 0x66, 0xf3, 0xc8, 0xed, 0xe1, 0x7d, 0x74, 0x7d, 0xe0, 0x64, - 0x11, 0xbd, 0xe6, 0xd0, 0x9b, 0x5d, 0x36, 0xee, 0xb3, 0x5e, 0x22, 0xac, 0xc1, 0xea, 0x0b, 0xc2, - 0x21, 0xa3, 0x17, 0x9d, 0xcb, 0xf5, 0xff, 0x71, 0x19, 0x1c, 0xfd, 0xa8, 0x66, 0x37, 0x36, 0x77, - 0x7e, 0xf5, 0xd0, 0x66, 0xd7, 0x65, 0x5f, 0x81, 0x04, 0x23, 0xcc, 0xa9, 0xa5, 0x16, 0xf0, 0x73, - 0xb4, 0x52, 0xb8, 0xae, 0x73, 0xad, 0x36, 0xda, 0xfb, 0x28, 0xbc, 0x7d, 0x5e, 0x84, 0x8b, 0x7d, - 0x7a, 0x70, 0xaf, 0xfe, 0x60, 0xdc, 0xf2, 0xf1, 0x0b, 0x34, 0xec, 0xdc, 0xb8, 0xfe, 0x1b, 0xed, - 0x4d, 0xfe, 0x4d, 0x6b, 0xda, 0x62, 0xbf, 0x96, 0x33, 0xd5, 0x2a, 0x5d, 0xf3, 0xf1, 0x63, 0xb4, - 0x2a, 0xe1, 0x9c, 0x38, 0xa6, 0x6b, 0xbf, 0x61, 0x3c, 0x94, 0x70, 0x7e, 0x58, 0xc7, 0x3b, 0x3f, - 0x2d, 0xa3, 0xb5, 0x3e, 0x1b, 0x1f, 0xa3, 0xb5, 0x66, 0x44, 0x11, 0x53, 0x7b, 0x6a, 0x9d, 0x7c, - 0x1c, 0x8a, 0x84, 0x85, 0xfd, 0x01, 0x16, 0xf6, 0x46, 0x56, 0xed, 0xc6, 0xed, 0xba, 0x32, 0xc4, - 0x23, 0x76, 0x13, 0xe0, 0x6f, 0xd1, 0x46, 0x7d, 0x69, 0x41, 0x9a, 0xd2, 0xb4, 0x92, 0x8d, 0xa1, - 0xf0, 0x3f, 0x25, 0x3b, 0x5a, 0xa3, 0xfa, 0x80, 0x2d, 0xc4, 0xf8, 0x18, 0x6d, 0x08, 0x29, 0xac, - 0xa0, 0x19, 0xa9, 0x68, 0x46, 0x0c, 0x58, 0x7f, 0x10, 0x0c, 0x26, 0xa3, 0xbd, 0xa0, 0xaf, 0x53, - 0x4f, 0xe2, 0xf0, 0x15, 0xcd, 0x04, 0xa7, 0x56, 0xe9, 0x6f, 0x0a, 0x4e, 0x2d, 0xb4, 0x15, 0x5a, - 0x6f, 0xe9, 0xaf, 0x68, 0x76, 0x0a, 0xf6, 0xe0, 0xf8, 0xf5, 0xe5, 0xd8, 0x7b, 0x73, 0x39, 0xf6, - 0xfe, 0xbc, 0x1c, 0x7b, 0x3f, 0x5f, 0x8d, 0x97, 0xde, 0x5c, 0x8d, 0x97, 0x7e, 0xbb, 0x1a, 0x2f, - 0x7d, 0xb7, 0x3f, 0x17, 0x36, 0x2d, 0x93, 0x90, 0xa9, 0x3c, 0x62, 0xca, 0xe4, 0xca, 0x44, 0x37, - 0x67, 0xf1, 0xf4, 0xfa, 0xe5, 0xa8, 0xf6, 0xa3, 0x1f, 0xdd, 0xf3, 0xe1, 0x06, 0x7f, 0xb2, 0xe2, - 0x2e, 0xd5, 0xa7, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x67, 0x6a, 0xf6, 0x66, 0x06, 0x00, - 0x00, + // 832 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xcf, 0x6f, 0xe4, 0x34, + 0x14, 0x6e, 0x3a, 0x4b, 0x3b, 0xf5, 0xf4, 0xc7, 0x62, 0xca, 0x12, 0xba, 0xd2, 0x74, 0xb6, 0x70, + 0x18, 0x81, 0x36, 0xa1, 0xa5, 0x12, 0x12, 0x37, 0xda, 0xb2, 0xec, 0xee, 0xa1, 0x9d, 0x4d, 0xcb, + 0x22, 0xc1, 0xc1, 0x72, 0xec, 0x37, 0x13, 0x8b, 0xc4, 0x8e, 0x6c, 0x27, 0xa5, 0x77, 0x24, 0xae, + 0x1c, 0xf9, 0x93, 0x96, 0xdb, 0x1e, 0x39, 0x01, 0x6a, 0xff, 0x11, 0x14, 0x27, 0x99, 0x66, 0x10, + 0x85, 0xe5, 0x96, 0x67, 0x7f, 0xdf, 0x17, 0x7f, 0xef, 0xf9, 0x3d, 0xa3, 0x4f, 0x84, 0xb4, 0xa0, + 0x59, 0x42, 0x85, 0x24, 0x06, 0x58, 0xa1, 0x85, 0xbd, 0x0a, 0x19, 0x2b, 0xc3, 0x72, 0x3f, 0x34, + 0x09, 0xd5, 0xc0, 0x09, 0x53, 0xd2, 0x14, 0x19, 0xe8, 0x20, 0xd7, 0xca, 0x2a, 0xbc, 0xf3, 0x0f, + 0x8c, 0x80, 0xb1, 0x32, 0x28, 0xf7, 0x77, 0x1e, 0x5a, 0x90, 0x1c, 0x74, 0x26, 0xa4, 0x0d, 0x69, + 0xcc, 0x44, 0x68, 0xaf, 0x72, 0x30, 0x35, 0x71, 0x27, 0x14, 0x31, 0x0b, 0x53, 0x31, 0x4b, 0x2c, + 0x4b, 0x05, 0x48, 0x6b, 0xc2, 0x0e, 0xba, 0xdc, 0xef, 0x44, 0x0d, 0x61, 0x38, 0x53, 0x6a, 0x96, + 0x42, 0xe8, 0xa2, 0xb8, 0x98, 0x86, 0xbc, 0xd0, 0xd4, 0x0a, 0x25, 0x9b, 0xfd, 0xed, 0x99, 0x9a, + 0x29, 0xf7, 0x19, 0x56, 0x5f, 0xf5, 0xea, 0xde, 0x8f, 0xab, 0x68, 0xf3, 0xb8, 0x39, 0xf2, 0x84, + 0x6a, 0x9a, 0x19, 0xec, 0xa3, 0x55, 0x90, 0x34, 0x4e, 0x81, 0xfb, 0xde, 0xc8, 0x1b, 0xf7, 0xa3, + 0x36, 0xc4, 0x67, 0xe8, 0xc3, 0x38, 0x55, 0xec, 0x7b, 0x43, 0x72, 0xd0, 0x84, 0x0b, 0x63, 0xb5, + 0x88, 0x8b, 0xea, 0x1f, 0xc4, 0x6a, 0x2a, 0x4d, 0x26, 0x8c, 0x11, 0x4a, 0xfa, 0xcb, 0x23, 0x6f, + 0xdc, 0x8b, 0x1e, 0xd5, 0xd8, 0x09, 0xe8, 0x93, 0x0e, 0xf2, 0xa2, 0x03, 0xc4, 0xcf, 0xd1, 0xa3, + 0x3b, 0x55, 0x08, 0x4b, 0xa8, 0x94, 0x90, 0xfa, 0xbd, 0x91, 0x37, 0x5e, 0x8b, 0x76, 0xf9, 0x1d, + 0x22, 0xc7, 0x35, 0x0c, 0x7f, 0x8e, 0x76, 0x72, 0xad, 0x4a, 0xc1, 0x41, 0x93, 0x29, 0x00, 0xc9, + 0x95, 0x4a, 0x09, 0xe5, 0x5c, 0x13, 0x63, 0xb5, 0x7f, 0xcf, 0x89, 0x3c, 0x68, 0x11, 0x4f, 0x00, + 0x26, 0x4a, 0xa5, 0x5f, 0x70, 0xae, 0xcf, 0xad, 0xc6, 0x2f, 0x10, 0x66, 0xac, 0x24, 0x56, 0x64, + 0xa0, 0x0a, 0x5b, 0xb9, 0x13, 0x8a, 0xfb, 0x6f, 0x8d, 0xbc, 0xf1, 0xe0, 0xe0, 0xfd, 0xa0, 0x4e, + 0x6c, 0xd0, 0x26, 0x36, 0x38, 0x69, 0x12, 0x7b, 0xd4, 0x7f, 0xf5, 0xfb, 0xee, 0xd2, 0x2f, 0x7f, + 0xec, 0x7a, 0xd1, 0x7d, 0xc6, 0xca, 0x8b, 0x9a, 0x3d, 0x71, 0x64, 0xfc, 0x1d, 0x7a, 0xcf, 0xb9, + 0x99, 0x82, 0xfe, 0xbb, 0xee, 0xca, 0x9b, 0xeb, 0xbe, 0xdb, 0x6a, 0x2c, 0x8a, 0x3f, 0x45, 0xa3, + 0xf6, 0x9e, 0x11, 0x0d, 0x0b, 0x29, 0x9c, 0x6a, 0xca, 0xaa, 0x0f, 0x7f, 0xd5, 0x39, 0x1e, 0xb6, + 0xb8, 0x68, 0x01, 0xf6, 0xa4, 0x41, 0xe1, 0xc7, 0x08, 0x27, 0xc2, 0x58, 0xa5, 0x05, 0xa3, 0x29, + 0x01, 0x69, 0xb5, 0x00, 0xe3, 0xf7, 0x5d, 0x01, 0xdf, 0xbe, 0xdd, 0xf9, 0xb2, 0xde, 0xc0, 0xa7, + 0xe8, 0x7e, 0x21, 0x63, 0x25, 0xb9, 0x90, 0xb3, 0xd6, 0xce, 0xda, 0x9b, 0xdb, 0xd9, 0x9a, 0x93, + 0x1b, 0x23, 0x9f, 0xa1, 0x07, 0x46, 0x4d, 0x2d, 0x51, 0xb9, 0x25, 0x55, 0x86, 0x6c, 0xa2, 0xc1, + 0x24, 0x2a, 0xe5, 0x3e, 0xaa, 0x8e, 0x7f, 0xb4, 0xec, 0x7b, 0xd1, 0x3b, 0x15, 0xe2, 0x2c, 0xb7, + 0x67, 0x85, 0xbd, 0x68, 0xb7, 0xf1, 0x07, 0x68, 0x43, 0xc3, 0x25, 0xd5, 0x9c, 0x70, 0x90, 0x2a, + 0x33, 0xfe, 0x60, 0xd4, 0x1b, 0xaf, 0x45, 0xeb, 0xf5, 0xe2, 0x89, 0x5b, 0xc3, 0x87, 0x68, 0x5e, + 0x70, 0xb2, 0x88, 0x5e, 0x77, 0xe8, 0xed, 0x76, 0x37, 0xea, 0xb2, 0x5e, 0x20, 0xac, 0xc1, 0xea, + 0x2b, 0xc2, 0x21, 0xa5, 0x57, 0xad, 0xcb, 0x8d, 0xff, 0x71, 0x19, 0x1c, 0xfd, 0xa4, 0x62, 0x37, + 0x36, 0x77, 0xd1, 0x60, 0x5e, 0x2f, 0xc1, 0xfd, 0x4d, 0x57, 0x1a, 0xd4, 0x2e, 0x3d, 0xe3, 0x7b, + 0xbf, 0x7a, 0x68, 0xbb, 0x6d, 0xc3, 0xaf, 0x40, 0x82, 0x11, 0xe6, 0xdc, 0x52, 0x0b, 0xf8, 0x29, + 0x5a, 0xc9, 0x5d, 0x5b, 0xba, 0x5e, 0x1c, 0x1c, 0x7c, 0x14, 0xdc, 0x3d, 0x50, 0x82, 0xc5, 0x46, + 0x3e, 0xba, 0x57, 0x9d, 0x28, 0x6a, 0xf8, 0xf8, 0x39, 0xea, 0xb7, 0x76, 0x5d, 0x83, 0x0e, 0x0e, + 0xc6, 0xff, 0xa6, 0x35, 0x69, 0xb0, 0xcf, 0xe4, 0x54, 0x35, 0x4a, 0x73, 0x3e, 0x7e, 0x88, 0xd6, + 0x24, 0x5c, 0x12, 0xc7, 0x74, 0xfd, 0xd9, 0x8f, 0xfa, 0x12, 0x2e, 0x8f, 0xab, 0x78, 0xef, 0xa7, + 0x65, 0xb4, 0xde, 0x65, 0xe3, 0x53, 0xb4, 0x5e, 0xcf, 0x30, 0x62, 0x2a, 0x4f, 0x8d, 0x93, 0x8f, + 0x03, 0x11, 0xb3, 0xa0, 0x3b, 0xe1, 0x82, 0xce, 0x4c, 0xab, 0xdc, 0xb8, 0x55, 0x97, 0x86, 0x68, + 0xc0, 0x6e, 0x03, 0xfc, 0x0d, 0xda, 0xaa, 0x52, 0x07, 0xd2, 0x14, 0xa6, 0x91, 0xac, 0x0d, 0x05, + 0xff, 0x29, 0xd9, 0xd2, 0x6a, 0xd5, 0x4d, 0xb6, 0x10, 0xe3, 0x53, 0xb4, 0x25, 0xa4, 0xb0, 0x82, + 0xa6, 0xa4, 0xa4, 0x29, 0x31, 0x60, 0xfd, 0xde, 0xa8, 0x37, 0x1e, 0x1c, 0x8c, 0xba, 0x3a, 0xd5, + 0xa8, 0x0e, 0x5e, 0xd2, 0x54, 0x70, 0x6a, 0x95, 0xfe, 0x3a, 0xe7, 0xd4, 0x42, 0x93, 0xa1, 0x8d, + 0x86, 0xfe, 0x92, 0xa6, 0xe7, 0x60, 0x8f, 0x4e, 0x5f, 0x5d, 0x0f, 0xbd, 0xd7, 0xd7, 0x43, 0xef, + 0xcf, 0xeb, 0xa1, 0xf7, 0xf3, 0xcd, 0x70, 0xe9, 0xf5, 0xcd, 0x70, 0xe9, 0xb7, 0x9b, 0xe1, 0xd2, + 0xb7, 0x87, 0x33, 0x61, 0x93, 0x22, 0x0e, 0x98, 0xca, 0x42, 0xa6, 0x4c, 0xa6, 0x4c, 0x78, 0x5b, + 0x8b, 0xc7, 0xf3, 0xa7, 0xa5, 0x3c, 0x0c, 0x7f, 0x70, 0xef, 0x8b, 0x7b, 0x19, 0xe2, 0x15, 0x77, + 0xeb, 0x3e, 0xfd, 0x2b, 0x00, 0x00, 0xff, 0xff, 0xc1, 0xf1, 0x1a, 0xba, 0x87, 0x06, 0x00, 0x00, } func (m *ConsumerParams) Marshal() (dAtA []byte, err error) { @@ -416,6 +426,13 @@ func (m *ConsumerParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.ConsumerId) > 0 { + i -= len(m.ConsumerId) + copy(dAtA[i:], m.ConsumerId) + i = encodeVarintSharedConsumer(dAtA, i, uint64(len(m.ConsumerId))) + i-- + dAtA[i] = 0x72 + } n1, err1 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.RetryDelayPeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.RetryDelayPeriod):]) if err1 != nil { return 0, err1 @@ -693,6 +710,10 @@ func (m *ConsumerParams) Size() (n int) { } l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.RetryDelayPeriod) n += 1 + l + sovSharedConsumer(uint64(l)) + l = len(m.ConsumerId) + if l > 0 { + n += 1 + l + sovSharedConsumer(uint64(l)) + } return n } @@ -1152,6 +1173,38 @@ func (m *ConsumerParams) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSharedConsumer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSharedConsumer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSharedConsumer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSharedConsumer(dAtA[iNdEx:]) diff --git a/x/ccv/types/shared_params.go b/x/ccv/types/shared_params.go index 566737c0b9..e3f8301b12 100644 --- a/x/ccv/types/shared_params.go +++ b/x/ccv/types/shared_params.go @@ -2,10 +2,14 @@ package types import ( fmt "fmt" + "strconv" + "strings" "time" ibchost "github.com/cosmos/ibc-go/v7/modules/core/24-host" + errorsmod "cosmossdk.io/errors" + sdktypes "github.com/cosmos/cosmos-sdk/types" ) @@ -112,3 +116,22 @@ func CalculateTrustPeriod(unbondingPeriod time.Duration, defaultTrustPeriodFract return trustPeriod, nil } + +// ValidateConsumerId validates the provided consumer id and returns an error if it is not valid +func ValidateConsumerId(i interface{}) error { + str, ok := i.(string) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + if strings.TrimSpace(str) == "" { + return errorsmod.Wrapf(ErrInvalidConsumerId, "consumer id cannot be blank") + } + + // check that `consumerId` corresponds to a `uint64` + _, err := strconv.ParseUint(str, 10, 64) + if err != nil { + return errorsmod.Wrapf(ErrInvalidConsumerId, "consumer id (%s) cannot be parsed: %s", str, err.Error()) + } + + return nil +} diff --git a/x/ccv/types/shared_params_test.go b/x/ccv/types/shared_params_test.go new file mode 100644 index 0000000000..9f73aaaf9d --- /dev/null +++ b/x/ccv/types/shared_params_test.go @@ -0,0 +1,23 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/interchain-security/v4/x/ccv/types" +) + +func TestValidateConsumerId(t *testing.T) { + // empty consumer id + require.Error(t, types.ValidateConsumerId("")) + + // not a `uint64` where `uint64` is in the range [0, 2^64) + require.Error(t, types.ValidateConsumerId("a")) + require.Error(t, types.ValidateConsumerId("-2545")) + require.Error(t, types.ValidateConsumerId("18446744073709551616")) // 2^64 + + // valid consumer id + require.NoError(t, types.ValidateConsumerId("0")) + require.NoError(t, types.ValidateConsumerId("18446744073709551615")) // 2^64 - 1 +} diff --git a/x/ccv/types/wire.go b/x/ccv/types/wire.go index 9c22522b74..ec04399380 100644 --- a/x/ccv/types/wire.go +++ b/x/ccv/types/wire.go @@ -1,6 +1,7 @@ package types import ( + "encoding/json" "fmt" errorsmod "cosmossdk.io/errors" @@ -194,3 +195,54 @@ func NewConsumerPacketData(cpdType ConsumerPacketDataType, data isConsumerPacket Data: data, } } + +type RewardMemo struct { + ConsumerId string `json:"consumerId"` + ChainId string `json:"chainId"` + Memo string `json:"memo"` +} + +func NewRewardMemo(consumerId, chainId, memo string) RewardMemo { + return RewardMemo{ + ConsumerId: consumerId, + ChainId: chainId, + Memo: memo, + } +} + +// CreateTransferMemo creates a memo for the IBC transfer of ICS rewards. +// Note that the memo follows the Fungible Token Transfer v2 standard +// https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md#using-the-memo-field +func CreateTransferMemo(consumerId, chainId string) (string, error) { + memo := NewRewardMemo(consumerId, chainId, "ICS rewards") + memoBytes, err := json.Marshal(memo) + if err != nil { + return "", err + } + return fmt.Sprintf(`{ + "provider": %s + }`, + string(memoBytes), + ), nil +} + +func GetRewardMemoFromTransferMemo(memo string) (RewardMemo, error) { + memoData := map[string]json.RawMessage{} + err := json.Unmarshal([]byte(memo), &memoData) + if err != nil { + return RewardMemo{}, err + } + + providerMemo, ok := memoData["provider"] + if !ok { + return RewardMemo{}, err + } + + rewardMemo := RewardMemo{} + err = json.Unmarshal([]byte(providerMemo), &rewardMemo) + if err != nil { + return RewardMemo{}, err + } + + return rewardMemo, nil +} diff --git a/x/ccv/types/wire_test.go b/x/ccv/types/wire_test.go index ab6692912e..a704fa3d2c 100644 --- a/x/ccv/types/wire_test.go +++ b/x/ccv/types/wire_test.go @@ -223,3 +223,17 @@ func TestVSCMaturedPacketDataWireBytes(t *testing.T) { require.Equal(t, expectedStr, str) } + +func TestCreateTransferMemo(t *testing.T) { + consumerId := "13" + chainId := "chain-13" + + transferMemo, err := types.CreateTransferMemo(consumerId, chainId) + require.NoError(t, err) + + rewardMemo, err := types.GetRewardMemoFromTransferMemo(transferMemo) + require.NoError(t, err) + require.Equal(t, consumerId, rewardMemo.ConsumerId) + require.Equal(t, chainId, rewardMemo.ChainId) + require.Equal(t, "ICS rewards", rewardMemo.Memo) +}