From da1dfd178a771357c0fc6d1e368cb5b66b48a628 Mon Sep 17 00:00:00 2001 From: shellvish <104537253+shellvish@users.noreply.github.com> Date: Thu, 7 Mar 2024 15:32:47 -0500 Subject: [PATCH] Add x/stakedym (#1126) --- app/app.go | 31 +- app/apptesting/test_helpers.go | 7 + app/upgrades.go | 3 +- proto/stride/stakedym/genesis.proto | 37 + proto/stride/stakedym/query.proto | 118 + proto/stride/stakedym/stakedym.proto | 208 + proto/stride/stakedym/tx.proto | 236 + x/stakedym/client/cli/parser.go | 151 + x/stakedym/client/cli/query.go | 292 + x/stakedym/client/cli/tx.go | 539 ++ x/stakedym/ibc_middleware.go | 198 + x/stakedym/keeper/abci.go | 16 + x/stakedym/keeper/delegation.go | 225 + x/stakedym/keeper/delegation_record.go | 116 + x/stakedym/keeper/delegation_record_test.go | 87 + x/stakedym/keeper/delegation_test.go | 550 ++ x/stakedym/keeper/events.go | 96 + x/stakedym/keeper/genesis.go | 57 + x/stakedym/keeper/grpc_query.go | 181 + x/stakedym/keeper/grpc_query_test.go | 257 + x/stakedym/keeper/hooks.go | 88 + x/stakedym/keeper/host_zone.go | 47 + x/stakedym/keeper/host_zone_test.go | 83 + x/stakedym/keeper/ibc.go | 81 + x/stakedym/keeper/ibc_test.go | 243 + x/stakedym/keeper/invariants.go | 30 + x/stakedym/keeper/invariants_test.go | 24 + x/stakedym/keeper/keeper.go | 46 + x/stakedym/keeper/keeper_test.go | 50 + x/stakedym/keeper/msg_server.go | 285 + x/stakedym/keeper/msg_server_test.go | 634 +++ x/stakedym/keeper/operator_test.go | 37 + x/stakedym/keeper/operatorlist.go | 59 + x/stakedym/keeper/redemption_rate.go | 139 + x/stakedym/keeper/redemption_rate_test.go | 234 + x/stakedym/keeper/redemption_record.go | 84 + x/stakedym/keeper/redemption_record_test.go | 155 + x/stakedym/keeper/slash_record.go | 56 + x/stakedym/keeper/slash_record_test.go | 73 + x/stakedym/keeper/transfer_callback.go | 69 + x/stakedym/keeper/transfer_callback_test.go | 96 + x/stakedym/keeper/unbonding.go | 411 ++ x/stakedym/keeper/unbonding_record.go | 130 + x/stakedym/keeper/unbonding_record_test.go | 131 + x/stakedym/keeper/unbonding_test.go | 1226 +++++ x/stakedym/module.go | 156 + x/stakedym/types/codec.go | 62 + x/stakedym/types/dymension.go | 20 + x/stakedym/types/errors.go | 32 + x/stakedym/types/events.go | 25 + x/stakedym/types/expected_keepers.go | 43 + x/stakedym/types/genesis.go | 71 + x/stakedym/types/genesis.pb.go | 1063 ++++ x/stakedym/types/host_zone.go | 125 + x/stakedym/types/host_zone_test.go | 348 ++ x/stakedym/types/keys.go | 55 + x/stakedym/types/msgs.go | 676 +++ x/stakedym/types/msgs_test.go | 950 ++++ x/stakedym/types/params.go | 16 + x/stakedym/types/query.pb.go | 2882 ++++++++++ x/stakedym/types/query.pb.gw.go | 590 ++ x/stakedym/types/records.go | 83 + x/stakedym/types/records_test.go | 213 + x/stakedym/types/stakedym.pb.go | 2740 ++++++++++ x/stakedym/types/tx.pb.go | 5460 +++++++++++++++++++ 65 files changed, 23524 insertions(+), 2 deletions(-) create mode 100644 proto/stride/stakedym/genesis.proto create mode 100644 proto/stride/stakedym/query.proto create mode 100644 proto/stride/stakedym/stakedym.proto create mode 100644 proto/stride/stakedym/tx.proto create mode 100644 x/stakedym/client/cli/parser.go create mode 100644 x/stakedym/client/cli/query.go create mode 100644 x/stakedym/client/cli/tx.go create mode 100644 x/stakedym/ibc_middleware.go create mode 100644 x/stakedym/keeper/abci.go create mode 100644 x/stakedym/keeper/delegation.go create mode 100644 x/stakedym/keeper/delegation_record.go create mode 100644 x/stakedym/keeper/delegation_record_test.go create mode 100644 x/stakedym/keeper/delegation_test.go create mode 100644 x/stakedym/keeper/events.go create mode 100644 x/stakedym/keeper/genesis.go create mode 100644 x/stakedym/keeper/grpc_query.go create mode 100644 x/stakedym/keeper/grpc_query_test.go create mode 100644 x/stakedym/keeper/hooks.go create mode 100644 x/stakedym/keeper/host_zone.go create mode 100644 x/stakedym/keeper/host_zone_test.go create mode 100644 x/stakedym/keeper/ibc.go create mode 100644 x/stakedym/keeper/ibc_test.go create mode 100644 x/stakedym/keeper/invariants.go create mode 100644 x/stakedym/keeper/invariants_test.go create mode 100644 x/stakedym/keeper/keeper.go create mode 100644 x/stakedym/keeper/keeper_test.go create mode 100644 x/stakedym/keeper/msg_server.go create mode 100644 x/stakedym/keeper/msg_server_test.go create mode 100644 x/stakedym/keeper/operator_test.go create mode 100644 x/stakedym/keeper/operatorlist.go create mode 100644 x/stakedym/keeper/redemption_rate.go create mode 100644 x/stakedym/keeper/redemption_rate_test.go create mode 100644 x/stakedym/keeper/redemption_record.go create mode 100644 x/stakedym/keeper/redemption_record_test.go create mode 100644 x/stakedym/keeper/slash_record.go create mode 100644 x/stakedym/keeper/slash_record_test.go create mode 100644 x/stakedym/keeper/transfer_callback.go create mode 100644 x/stakedym/keeper/transfer_callback_test.go create mode 100644 x/stakedym/keeper/unbonding.go create mode 100644 x/stakedym/keeper/unbonding_record.go create mode 100644 x/stakedym/keeper/unbonding_record_test.go create mode 100644 x/stakedym/keeper/unbonding_test.go create mode 100644 x/stakedym/module.go create mode 100644 x/stakedym/types/codec.go create mode 100644 x/stakedym/types/dymension.go create mode 100644 x/stakedym/types/errors.go create mode 100644 x/stakedym/types/events.go create mode 100644 x/stakedym/types/expected_keepers.go create mode 100644 x/stakedym/types/genesis.go create mode 100644 x/stakedym/types/genesis.pb.go create mode 100644 x/stakedym/types/host_zone.go create mode 100644 x/stakedym/types/host_zone_test.go create mode 100644 x/stakedym/types/keys.go create mode 100644 x/stakedym/types/msgs.go create mode 100644 x/stakedym/types/msgs_test.go create mode 100644 x/stakedym/types/params.go create mode 100644 x/stakedym/types/query.pb.go create mode 100644 x/stakedym/types/query.pb.gw.go create mode 100644 x/stakedym/types/records.go create mode 100644 x/stakedym/types/records_test.go create mode 100644 x/stakedym/types/stakedym.pb.go create mode 100644 x/stakedym/types/tx.pb.go diff --git a/app/app.go b/app/app.go index fa857de010..c73c23098d 100644 --- a/app/app.go +++ b/app/app.go @@ -145,6 +145,9 @@ import ( recordsmodule "github.com/Stride-Labs/stride/v18/x/records" recordsmodulekeeper "github.com/Stride-Labs/stride/v18/x/records/keeper" recordsmoduletypes "github.com/Stride-Labs/stride/v18/x/records/types" + stakedym "github.com/Stride-Labs/stride/v18/x/stakedym" + stakedymkeeper "github.com/Stride-Labs/stride/v18/x/stakedym/keeper" + stakedymtypes "github.com/Stride-Labs/stride/v18/x/stakedym/types" stakeibcmodule "github.com/Stride-Labs/stride/v18/x/stakeibc" stakeibcclient "github.com/Stride-Labs/stride/v18/x/stakeibc/client" stakeibcmodulekeeper "github.com/Stride-Labs/stride/v18/x/stakeibc/keeper" @@ -218,6 +221,7 @@ var ( packetforward.AppModuleBasic{}, evmosvesting.AppModuleBasic{}, staketia.AppModuleBasic{}, + stakedym.AppModuleBasic{}, wasm.AppModuleBasic{}, ) @@ -240,6 +244,8 @@ var ( stakeibcmoduletypes.RewardCollectorName: nil, staketiatypes.ModuleName: {authtypes.Minter, authtypes.Burner}, staketiatypes.FeeAddress: nil, + stakedymtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + stakedymtypes.FeeAddress: nil, wasmtypes.ModuleName: {authtypes.Burner}, } ) @@ -321,6 +327,7 @@ type StrideApp struct { ClaimKeeper claimkeeper.Keeper ICAOracleKeeper icaoraclekeeper.Keeper StaketiaKeeper staketiakeeper.Keeper + StakedymKeeper stakedymkeeper.Keeper mm *module.Manager sm *module.SimulationManager @@ -372,6 +379,7 @@ func NewStrideApp( packetforwardtypes.StoreKey, evmosvestingtypes.StoreKey, staketiatypes.StoreKey, + stakedymtypes.StoreKey, wasmtypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) @@ -635,6 +643,18 @@ func NewStrideApp( ) stakeTiaModule := staketia.NewAppModule(appCodec, app.StaketiaKeeper) + // Stakedym Keeper must be initialized after TransferKeeper + app.StakedymKeeper = *stakedymkeeper.NewKeeper( + appCodec, + keys[stakedymtypes.StoreKey], + app.AccountKeeper, + app.BankKeeper, + app.ICAOracleKeeper, + app.RatelimitKeeper, + app.TransferKeeper, + ) + stakeDymModule := stakedym.NewAppModule(appCodec, app.StakedymKeeper) + app.VestingKeeper = evmosvestingkeeper.NewKeeper( keys[evmosvestingtypes.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName), appCodec, app.AccountKeeper, app.BankKeeper, app.DistrKeeper, app.StakingKeeper, @@ -701,6 +721,7 @@ func NewStrideApp( app.MintKeeper.Hooks(), app.ClaimKeeper.Hooks(), app.StaketiaKeeper.Hooks(), + app.StakedymKeeper.Hooks(), ), ) epochsModule := epochsmodule.NewAppModule(appCodec, app.EpochsKeeper) @@ -758,6 +779,7 @@ func NewStrideApp( // - autopilot // - records // - staketia + // - stakedym // - ratelimit // - pfm // - transfer @@ -774,6 +796,7 @@ func NewStrideApp( ) transferStack = ratelimit.NewIBCMiddleware(app.RatelimitKeeper, transferStack) transferStack = staketia.NewIBCMiddleware(app.StaketiaKeeper, transferStack) + transferStack = stakedym.NewIBCMiddleware(app.StakedymKeeper, transferStack) transferStack = recordsmodule.NewIBCModule(app.RecordsKeeper, transferStack) transferStack = autopilot.NewIBCModule(app.AutopilotKeeper, transferStack) @@ -840,6 +863,7 @@ func NewStrideApp( autopilotModule, icaoracleModule, stakeTiaModule, + stakeDymModule, ) // During begin block slashing happens after distr.BeginBlocker so that @@ -880,6 +904,7 @@ func NewStrideApp( consensusparamtypes.ModuleName, packetforwardtypes.ModuleName, staketiatypes.ModuleName, + stakedymtypes.ModuleName, wasmtypes.ModuleName, ) @@ -917,6 +942,7 @@ func NewStrideApp( consensusparamtypes.ModuleName, packetforwardtypes.ModuleName, staketiatypes.ModuleName, + stakedymtypes.ModuleName, wasmtypes.ModuleName, ) @@ -959,6 +985,7 @@ func NewStrideApp( consensusparamtypes.ModuleName, packetforwardtypes.ModuleName, staketiatypes.ModuleName, + stakedymtypes.ModuleName, wasmtypes.ModuleName, ) @@ -1133,7 +1160,9 @@ func (app *StrideApp) BlacklistedModuleAccountAddrs() map[string]bool { acc == stakeibcmoduletypes.RewardCollectorName || acc == ccvconsumertypes.ConsumerToSendToProviderName || acc == staketiatypes.ModuleName || - acc == staketiatypes.FeeAddress { + acc == staketiatypes.FeeAddress || + acc == stakedymtypes.ModuleName || + acc == stakedymtypes.FeeAddress { continue } modAccAddrs[authtypes.NewModuleAddress(acc).String()] = true diff --git a/app/apptesting/test_helpers.go b/app/apptesting/test_helpers.go index 11cc0bc2a5..e3a3430980 100644 --- a/app/apptesting/test_helpers.go +++ b/app/apptesting/test_helpers.go @@ -96,6 +96,13 @@ func (s *AppTestHelper) Setup() { for _, unbondingRecord := range s.App.StaketiaKeeper.GetAllActiveUnbondingRecords(s.Ctx) { s.App.StaketiaKeeper.RemoveUnbondingRecord(s.Ctx, unbondingRecord.Id) } + + // Remove host zone and accumulating record for stakedym, by default, + // since the tests will override it directly if needed + s.App.StakedymKeeper.RemoveHostZone(s.Ctx) + for _, unbondingRecord := range s.App.StakedymKeeper.GetAllActiveUnbondingRecords(s.Ctx) { + s.App.StakedymKeeper.RemoveUnbondingRecord(s.Ctx, unbondingRecord.Id) + } } // Instantiates an TestHelper without the test suite diff --git a/app/upgrades.go b/app/upgrades.go index 07e3b4e2f2..92089ed36d 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -40,6 +40,7 @@ import ( icacallbacktypes "github.com/Stride-Labs/stride/v18/x/icacallbacks/types" icaoracletypes "github.com/Stride-Labs/stride/v18/x/icaoracle/types" recordtypes "github.com/Stride-Labs/stride/v18/x/records/types" + stakedymtypes "github.com/Stride-Labs/stride/v18/x/stakedym/types" stakeibctypes "github.com/Stride-Labs/stride/v18/x/stakeibc/types" staketiatypes "github.com/Stride-Labs/stride/v18/x/staketia/types" ) @@ -314,7 +315,7 @@ func (app *StrideApp) setupUpgradeHandlers(appOpts servertypes.AppOptions) { } case "v19": storeUpgrades = &storetypes.StoreUpgrades{ - Added: []string{wasmtypes.ModuleName}, + Added: []string{wasmtypes.ModuleName, stakedymtypes.ModuleName}, } } diff --git a/proto/stride/stakedym/genesis.proto b/proto/stride/stakedym/genesis.proto new file mode 100644 index 0000000000..2df34752cf --- /dev/null +++ b/proto/stride/stakedym/genesis.proto @@ -0,0 +1,37 @@ +syntax = "proto3"; +package stride.stakedym; + +import "gogoproto/gogo.proto"; +import "stride/stakedym/stakedym.proto"; + +option go_package = "github.com/Stride-Labs/stride/v18/x/stakedym/types"; + +// Params defines the stakedym module parameters. +message Params {} + +// TransferInProgressRecordIds stores record IDs for delegation records +// that have a transfer in progress +message TransferInProgressRecordIds { + string channel_id = 1; + uint64 sequence = 2; + uint64 record_id = 3; +} + +// GenesisState defines the stakedym module's genesis state. +message GenesisState { + Params params = 1 [ + (gogoproto.moretags) = "yaml:\"params\"", + (gogoproto.nullable) = false + ]; + + HostZone host_zone = 2 [ (gogoproto.nullable) = false ]; + repeated DelegationRecord delegation_records = 3 + [ (gogoproto.nullable) = false ]; + repeated UnbondingRecord unbonding_records = 4 + [ (gogoproto.nullable) = false ]; + repeated RedemptionRecord redemption_records = 5 + [ (gogoproto.nullable) = false ]; + repeated SlashRecord slash_records = 6 [ (gogoproto.nullable) = false ]; + repeated TransferInProgressRecordIds transfer_in_progress_record_ids = 7 + [ (gogoproto.nullable) = false ]; +} \ No newline at end of file diff --git a/proto/stride/stakedym/query.proto b/proto/stride/stakedym/query.proto new file mode 100644 index 0000000000..657d9e0973 --- /dev/null +++ b/proto/stride/stakedym/query.proto @@ -0,0 +1,118 @@ + +syntax = "proto3"; +package stride.stakedym; + +import "stride/stakedym/stakedym.proto"; +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; + +option go_package = "github.com/Stride-Labs/stride/v18/x/stakedym/types"; + +// Query defines the gRPC querier service. +service Query { + // Queries the host zone struct + rpc HostZone(QueryHostZoneRequest) returns (QueryHostZoneResponse) { + option (google.api.http).get = "/Stride-Labs/stride/stakedym/host_zone"; + } + + // Queries the delegation records with an optional to include archived records + // Ex: + // - /delegation_records + // - /delegation_records?include_archived=true + rpc DelegationRecords(QueryDelegationRecordsRequest) + returns (QueryDelegationRecordsResponse) { + option (google.api.http).get = + "/Stride-Labs/stride/stakedym/delegation_records"; + } + + // Queries the unbonding records with an optional to include archived records + // Ex: + // - /unbonding_records + // - /unbonding_records?include_archived=true + rpc UnbondingRecords(QueryUnbondingRecordsRequest) + returns (QueryUnbondingRecordsResponse) { + option (google.api.http).get = + "/Stride-Labs/stride/stakedym/unbonding_records"; + } + + // Queries a single user redemption record + rpc RedemptionRecord(QueryRedemptionRecordRequest) + returns (QueryRedemptionRecordResponse) { + option (google.api.http).get = + "/Stride-Labs/stride/stakedym/redemption_record/{unbonding_record_id}/" + "{address}"; + } + + // Queries all redemption records with optional filters + // Ex: + // - /redemption_records + // - /redemption_records?address=strideXXX + // - /redemption_records?unbonding_record_id=100 + rpc RedemptionRecords(QueryRedemptionRecordsRequest) + returns (QueryRedemptionRecordsResponse) { + option (google.api.http).get = + "/Stride-Labs/stride/stakedym/redemption_records"; + } + + // Queries slash records + rpc SlashRecords(QuerySlashRecordsRequest) + returns (QuerySlashRecordsResponse) { + option (google.api.http).get = "/Stride-Labs/stride/stakedym/slash_records"; + } +} + +// Host Zone +message QueryHostZoneRequest {}; +message QueryHostZoneResponse { HostZone host_zone = 1; } + +// All Delegation Records +message QueryDelegationRecordsRequest { bool include_archived = 1; }; +message QueryDelegationRecordsResponse { + repeated DelegationRecord delegation_records = 1 + [ (gogoproto.nullable) = false ]; +} + +// All Unbonding Records +message QueryUnbondingRecordsRequest { bool include_archived = 1; }; +message QueryUnbondingRecordsResponse { + repeated UnbondingRecord unbonding_records = 1 + [ (gogoproto.nullable) = false ]; +} + +// Single Redemption Record +message QueryRedemptionRecordRequest { + uint64 unbonding_record_id = 1; + string address = 2; +}; +message QueryRedemptionRecordResponse { + RedemptionRecordResponse redemption_record_response = 1; +} + +// All Redemption Records +message QueryRedemptionRecordsRequest { + string address = 1; + uint64 unbonding_record_id = 2; + cosmos.base.query.v1beta1.PageRequest pagination = 3; +}; +message QueryRedemptionRecordsResponse { + repeated RedemptionRecordResponse redemption_record_responses = 1 + [ (gogoproto.nullable) = false ]; + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// All Slash Records +message QuerySlashRecordsRequest {}; +message QuerySlashRecordsResponse { + repeated SlashRecord slash_records = 1 [ (gogoproto.nullable) = false ]; +} + +// Data structure for frontend to consume +message RedemptionRecordResponse { + // Redemption record + RedemptionRecord redemption_record = 1; + + // The Unix timestamp (in seconds) at which the unbonding for the UR + // associated with this RR completes + uint64 unbonding_completion_time_seconds = 2; +} \ No newline at end of file diff --git a/proto/stride/stakedym/stakedym.proto b/proto/stride/stakedym/stakedym.proto new file mode 100644 index 0000000000..5f608ad5ac --- /dev/null +++ b/proto/stride/stakedym/stakedym.proto @@ -0,0 +1,208 @@ +syntax = "proto3"; +package stride.stakedym; + +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/Stride-Labs/stride/v18/x/stakedym/types"; + +message HostZone { + // Chain ID + string chain_id = 1; + // Native token denom on the host zone (e.g. adym) + string native_token_denom = 2; + // IBC denom of the native token as it lives on stride (e.g. ibc/...) + string native_token_ibc_denom = 3; + // Transfer channel ID from stride to the host zone + string transfer_channel_id = 4; + + // Operator controlled delegation address on the host zone + string delegation_address = 5 + [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // Operator controlled reward address on the host zone + string reward_address = 6 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // Deposit address on stride + string deposit_address = 7 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // Redemption address on stride + string redemption_address = 8 + [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // Claim address on stride + string claim_address = 9 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // operator address set by safe, on stride + string operator_address_on_stride = 10 + [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // admin address set upon host zone creation, on stride + string safe_address_on_stride = 11 + [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // Previous redemption rate + string last_redemption_rate = 12 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + // Current redemption rate + string redemption_rate = 13 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + // Min outer redemption rate - adjusted by governance + string min_redemption_rate = 14 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + // Max outer redemption rate - adjusted by governance + string max_redemption_rate = 15 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + // Min inner redemption rate - adjusted by controller + string min_inner_redemption_rate = 16 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + // Max inner redemption rate - adjusted by controller + string max_inner_redemption_rate = 17 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + + // Total delegated balance on the host zone delegation account + string delegated_balance = 18 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + + // The undelegation period for Dymension in days + uint64 unbonding_period_seconds = 19; + // Indicates whether the host zone has been halted + bool halted = 20; +} + +// Status fields for a delegation record +// Note: There is an important assumption here that tokens in the deposit +// account should not be tracked by these records. The record is created as soon +// as the tokens leave stride +// Additionally, the GetActiveDelegationRecords query filters for records that +// are either TRANSFER_IN_PROGERSS or DELEGATION_QUEUE. If a new active status +// is added, the keeper must be modified +enum DelegationRecordStatus { + option (gogoproto.goproto_enum_prefix) = false; + + // TRANSFER_IN_PROGRESS indicates the native tokens are being sent from the + // deposit account to the delegation account + TRANSFER_IN_PROGRESS = 0; + // TRANSFER_FAILED indicates that the transfer either timed out or was an ack + // failure + TRANSFER_FAILED = 1; + // DELEGATION_QUEUE indicates the tokens have landed on the host zone and are + // ready to be delegated + DELEGATION_QUEUE = 2; + // DELEGATION_COMPLETE indicates the delegation has been completed + DELEGATION_COMPLETE = 3; +} + +// Status fields for an unbonding record +enum UnbondingRecordStatus { + option (gogoproto.goproto_enum_prefix) = false; + + // ACCUMULATING_REDEMPTIONS indicates redemptions are still being accumulated + // on this record + ACCUMULATING_REDEMPTIONS = 0; + // UNBONDING_QUEUE indicates the unbond amount for this epoch has been froze + // and the tokens are ready to be unbonded on the host zone + UNBONDING_QUEUE = 1; + // UNBONDING_IN_PROGRESS indicates the unbonding is currently in progress on + // the host zone + UNBONDING_IN_PROGRESS = 2; + // UNBONDED indicates the unbonding is finished on the host zone and the + // tokens are still in the delegation account + UNBONDED = 3; + // CLAIMABLE indicates the unbonded tokens have been swept to stride and are + // ready to be distributed to users + CLAIMABLE = 4; + // CLAIMED indicates the full unbonding cycle has been completed + CLAIMED = 5; +} + +// DelegationRecords track the aggregate liquid stakes and delegations +// for a given epoch +// Note: There is an important assumption here that tokens in the deposit +// account should not be tracked by these records. The record is created as soon +// as the tokens leave stride +message DelegationRecord { + // Deposit record unique ID + uint64 id = 1; + // The amount of native tokens that should be delegated + string native_amount = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // The status indicating the point in the delegation's lifecycle + DelegationRecordStatus status = 3; + // The tx hash of the delegation on the host zone + string tx_hash = 4; +} + +// UnbondingRecords track the aggregate unbondings across an epoch +message UnbondingRecord { + // Unbonding record ID + uint64 id = 1; + // The status indicating the point in the delegation's lifecycle + UnbondingRecordStatus status = 2; + // The amount of stTokens that were redeemed + string st_token_amount = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // The corresponding amount of native tokens that should be unbonded + string native_amount = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // The Unix timestamp (in seconds) at which the unbonding completes + uint64 unbonding_completion_time_seconds = 5; + // The tx hash of the undelegation on the host zone + string undelegation_tx_hash = 6; + // The tx hash of the unbonded token sweep on the host zone + string unbonded_token_sweep_tx_hash = 7; +} + +// RedemptionRecords track an individual user's redemption claims +message RedemptionRecord { + // Unbonding record ID + uint64 unbonding_record_id = 1; + // Redeemer + string redeemer = 2; + // The amount of stTokens that were redeemed + string st_token_amount = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // The corresponding amount of native tokens that should be unbonded + string native_amount = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; +} + +// SlashRecords log adjustments to the delegated balance +message SlashRecord { + // The slash record monotonically increasing ID + uint64 id = 1; + // The Unix timestamp (in seconds) when the slash adjustment was processed on + // stride + uint64 time = 2; + // The delta by which the total delegated amount changed from slash + string native_amount = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // The address (or addresses) of the validator that was slashed + string validator_address = 4; +} \ No newline at end of file diff --git a/proto/stride/stakedym/tx.proto b/proto/stride/stakedym/tx.proto new file mode 100644 index 0000000000..e1a4a7a60c --- /dev/null +++ b/proto/stride/stakedym/tx.proto @@ -0,0 +1,236 @@ + +syntax = "proto3"; +package stride.stakedym; + +import "cosmos/msg/v1/msg.proto"; +import "amino/amino.proto"; +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos_proto/cosmos.proto"; +import "stride/stakedym/stakedym.proto"; + +option go_package = "github.com/Stride-Labs/stride/v18/x/stakedym/types"; + +enum OverwritableRecordType { + option (gogoproto.goproto_enum_prefix) = false; + + RECORD_TYPE_DELEGATION = 0; + RECORD_TYPE_UNBONDING = 1; + RECORD_TYPE_REDEMPTION = 2; +} + +// Msg defines the Msg service. +service Msg { + // User transaction to liquid stake native tokens into stTokens + rpc LiquidStake(MsgLiquidStake) returns (MsgLiquidStakeResponse); + + // User transaction to redeem stake stTokens into native tokens + rpc RedeemStake(MsgRedeemStake) returns (MsgRedeemStakeResponse); + + // Operator transaction to confirm a delegation was submitted + // on the host chain + rpc ConfirmDelegation(MsgConfirmDelegation) + returns (MsgConfirmDelegationResponse); + + // Operator transaction to confirm an undelegation was submitted + // on the host chain + rpc ConfirmUndelegation(MsgConfirmUndelegation) + returns (MsgConfirmUndelegationResponse); + + // Operator transaction to confirm unbonded tokens were transferred back to + // stride + rpc ConfirmUnbondedTokenSweep(MsgConfirmUnbondedTokenSweep) + returns (MsgConfirmUnbondedTokenSweepResponse); + + // Operator transaction to adjust the delegated balance after a validator was + // slashed + rpc AdjustDelegatedBalance(MsgAdjustDelegatedBalance) + returns (MsgAdjustDelegatedBalanceResponse); + + // Adjusts the inner redemption rate bounds on the host zone + rpc UpdateInnerRedemptionRateBounds(MsgUpdateInnerRedemptionRateBounds) + returns (MsgUpdateInnerRedemptionRateBoundsResponse); + + // Unhalts the host zone if redemption rates were exceeded + rpc ResumeHostZone(MsgResumeHostZone) returns (MsgResumeHostZoneResponse); + + // Trigger updating the redemption rate + rpc RefreshRedemptionRate(MsgRefreshRedemptionRate) + returns (MsgRefreshRedemptionRateResponse); + + // Overwrites a delegation record + rpc OverwriteDelegationRecord(MsgOverwriteDelegationRecord) + returns (MsgOverwriteDelegationRecordResponse); + + // Overwrites a unbonding record + rpc OverwriteUnbondingRecord(MsgOverwriteUnbondingRecord) + returns (MsgOverwriteUnbondingRecordResponse); + + // Overwrites a redemption record + rpc OverwriteRedemptionRecord(MsgOverwriteRedemptionRecord) + returns (MsgOverwriteRedemptionRecordResponse); + + // Sets the operator address + rpc SetOperatorAddress(MsgSetOperatorAddress) + returns (MsgSetOperatorAddressResponse); +} + +// LiquidStake +message MsgLiquidStake { + option (cosmos.msg.v1.signer) = "staker"; + option (amino.name) = "stakedym/MsgLiquidStake"; + + string staker = 1; + string native_amount = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; +} +message MsgLiquidStakeResponse { + cosmos.base.v1beta1.Coin st_token = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// RedeemStake +message MsgRedeemStake { + option (cosmos.msg.v1.signer) = "redeemer"; + option (amino.name) = "stakedym/MsgRedeemStake"; + + string redeemer = 1; + string st_token_amount = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; +} +message MsgRedeemStakeResponse { + cosmos.base.v1beta1.Coin native_token = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// ConfirmDelegation +message MsgConfirmDelegation { + option (cosmos.msg.v1.signer) = "operator"; + option (amino.name) = "stakedym/MsgConfirmDelegation"; + + string operator = 1; + uint64 record_id = 2; + string tx_hash = 3; +} +message MsgConfirmDelegationResponse {} + +// ConfirmUndelegation +message MsgConfirmUndelegation { + option (cosmos.msg.v1.signer) = "operator"; + option (amino.name) = "stakedym/MsgConfirmUndelegation"; + + string operator = 1; + uint64 record_id = 2; + string tx_hash = 3; +} +message MsgConfirmUndelegationResponse {} + +// ConfirmUnbondedTokenSweep +message MsgConfirmUnbondedTokenSweep { + option (cosmos.msg.v1.signer) = "operator"; + option (amino.name) = "stakedym/MsgConfirmUnbondedTokenSweep"; + + string operator = 1; + uint64 record_id = 2; + string tx_hash = 3; +} +message MsgConfirmUnbondedTokenSweepResponse {} + +// AdjustDelegatedBalance +message MsgAdjustDelegatedBalance { + option (cosmos.msg.v1.signer) = "operator"; + option (amino.name) = "stakedym/MsgAdjustDelegatedBalance"; + + string operator = 1; + string delegation_offset = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + string validator_address = 3; +} +message MsgAdjustDelegatedBalanceResponse {} + +// UpdateInnerRedemptionRate +message MsgUpdateInnerRedemptionRateBounds { + option (cosmos.msg.v1.signer) = "creator"; + option (amino.name) = "stakedym/MsgUpdateRedemptionRateBounds"; + + string creator = 1; + string min_inner_redemption_rate = 2 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + string max_inner_redemption_rate = 3 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} +message MsgUpdateInnerRedemptionRateBoundsResponse {} + +// ResumeHostZone +message MsgResumeHostZone { + option (cosmos.msg.v1.signer) = "creator"; + option (amino.name) = "stakedym/MsgResumeHostZone"; + + string creator = 1; +} +message MsgResumeHostZoneResponse {} + +// RefreshRedemptionRate +message MsgRefreshRedemptionRate { + option (cosmos.msg.v1.signer) = "creator"; + option (amino.name) = "stakedym/MsgRefreshRedemptionRate"; + + string creator = 1; +} +message MsgRefreshRedemptionRateResponse {} + +// OverwriteDelegationRecord +message MsgOverwriteDelegationRecord { + option (cosmos.msg.v1.signer) = "creator"; + option (amino.name) = "stakedym/MsgOverwriteDelegationRecord"; + + string creator = 1; + DelegationRecord delegation_record = 2; +} +message MsgOverwriteDelegationRecordResponse {} + +// OverwriteUnbondingRecord +message MsgOverwriteUnbondingRecord { + option (cosmos.msg.v1.signer) = "creator"; + option (amino.name) = "stakedym/MsgOverwriteUnbondingRecord"; + + string creator = 1; + UnbondingRecord unbonding_record = 2; +} +message MsgOverwriteUnbondingRecordResponse {} + +// OverwriteRedemptionRecord +message MsgOverwriteRedemptionRecord { + option (cosmos.msg.v1.signer) = "creator"; + option (amino.name) = "stakedym/MsgOverwriteRedemptionRecord"; + + string creator = 1; + RedemptionRecord redemption_record = 2; +} +message MsgOverwriteRedemptionRecordResponse {} + +// SetOperatorAddress +message MsgSetOperatorAddress { + option (cosmos.msg.v1.signer) = "signer"; + option (amino.name) = "stakedym/MsgSetOperatorAddress"; + + string signer = 1; + string operator = 2; +} +message MsgSetOperatorAddressResponse {} diff --git a/x/stakedym/client/cli/parser.go b/x/stakedym/client/cli/parser.go new file mode 100644 index 0000000000..1985d1ba5f --- /dev/null +++ b/x/stakedym/client/cli/parser.go @@ -0,0 +1,151 @@ +package cli + +import ( + "os" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/gogo/protobuf/proto" + "github.com/spf13/cobra" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +////////////////////////////////////////////// +// LOGIC FOR PARSING OVERWRITE RECORD JSONS // +////////////////////////////////////////////// + +// Parse the overwrite delegationrecord json file into a proto message +func parseOverwriteDelegationRecordFile(cdc codec.JSONCodec, + parseOverWriteRecordFile string, + delegationRecord proto.Message, +) (err error) { + // Defer with a recover to set the error, + // if an expected sdk.Int field is not included in the JSON + // will panic and the CLI can SEGFAULT + defer func() { + if r := recover(); r != nil { + err = sdkerrors.ErrInvalidRequest + } + }() + + contents, err := os.ReadFile(parseOverWriteRecordFile) + if err != nil { + return err + } + + if err = cdc.UnmarshalJSON(contents, delegationRecord); err != nil { + return err + } + + return err +} + +// Parse the overwrite unbondingrecord json file into a proto message +func parseOverwriteUnbondingRecordFile(cdc codec.JSONCodec, + parseOverWriteRecordFile string, + unbondingRecord proto.Message, +) (err error) { + // Defer with a recover to set the error, + // if an expected sdk.Int field is not included in the JSON + // will panic and the CLI can SEGFAULT + defer func() { + if r := recover(); r != nil { + err = sdkerrors.ErrInvalidRequest + } + }() + + contents, err := os.ReadFile(parseOverWriteRecordFile) + if err != nil { + return err + } + + if err = cdc.UnmarshalJSON(contents, unbondingRecord); err != nil { + return err + } + + return err +} + +// Parse the overwrite redemptionrecord json file into a proto message +func parseOverwriteRedemptionRecordFile(cdc codec.JSONCodec, + parseOverWriteRecordFile string, + redemptionRecord proto.Message, +) (err error) { + // Defer with a recover to set the error, + // if an expected sdk.Int field is not included in the JSON + // will panic and the CLI can SEGFAULT + defer func() { + if r := recover(); r != nil { + err = sdkerrors.ErrInvalidRequest + } + }() + + contents, err := os.ReadFile(parseOverWriteRecordFile) + if err != nil { + return err + } + + if err = cdc.UnmarshalJSON(contents, redemptionRecord); err != nil { + return err + } + + return err +} + +////////////////////////////////////////////// +// LOGIC FOR BROADCASTING OVERWRITE RECORDS // +////////////////////////////////////////////// + +// helper to parse delegation record and broadcast OverwriteDelegationRecord +func parseAndBroadcastOverwriteDelegation(clientCtx client.Context, cmd *cobra.Command, recordContents string) error { + var delegationRecord types.DelegationRecord + // parse the input json + if err := parseOverwriteDelegationRecordFile(clientCtx.Codec, recordContents, &delegationRecord); err != nil { + return err + } + msg := types.NewMsgOverwriteDelegationRecord( + clientCtx.GetFromAddress().String(), + delegationRecord, + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) +} + +// helper to parse unbonding record and broadcast OverwriteUnbondingRecord +func parseAndBroadcastOverwriteUnbonding(clientCtx client.Context, cmd *cobra.Command, recordContents string) error { + var unbondingRecord types.UnbondingRecord + // parse the input json + if err := parseOverwriteUnbondingRecordFile(clientCtx.Codec, recordContents, &unbondingRecord); err != nil { + return err + } + msg := types.NewMsgOverwriteUnbondingRecord( + clientCtx.GetFromAddress().String(), + unbondingRecord, + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) +} + +// helper to parse redemption record and broadcast OverwriteRedemptionRecord +func parseAndBroadcastOverwriteRedemption(clientCtx client.Context, cmd *cobra.Command, recordContents string) error { + var redemptionRecord types.RedemptionRecord + // parse the input json + if err := parseOverwriteRedemptionRecordFile(clientCtx.Codec, recordContents, &redemptionRecord); err != nil { + return err + } + msg := types.NewMsgOverwriteRedemptionRecord( + clientCtx.GetFromAddress().String(), + redemptionRecord, + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) +} diff --git a/x/stakedym/client/cli/query.go b/x/stakedym/client/cli/query.go new file mode 100644 index 0000000000..bb8e08f22b --- /dev/null +++ b/x/stakedym/client/cli/query.go @@ -0,0 +1,292 @@ +package cli + +import ( + "context" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/version" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +const ( + FlagInlcudeArchived = "include-archived" + FlagAddress = "address" + FlagUnbondingRecordId = "unbonding-record-id" +) + +// GetQueryCmd returns the cli query commands for this module. +func GetQueryCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + CmdQueryHostZone(), + CmdQueryDelegationRecords(), + CmdQueryUnbondingRecords(), + CmdQueryRedemptionRecord(), + CmdQueryRedemptionRecords(), + CmdQuerySlashRecords(), + ) + + return cmd +} + +// CmdQueryHostZone implements a command to query the host zone struct +func CmdQueryHostZone() *cobra.Command { + cmd := &cobra.Command{ + Use: "host-zone", + Short: "Queries the host zone struct", + Long: strings.TrimSpace( + fmt.Sprintf(`Queries the host zone +Example: + $ %s query %s host-zone +`, version.AppName, types.ModuleName), + ), + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryHostZoneRequest{} + res, err := queryClient.HostZone(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + return cmd +} + +// Queries delegation records with an option to include archive records +func CmdQueryDelegationRecords() *cobra.Command { + cmd := &cobra.Command{ + Use: "delegation-records", + Short: "Queries all delegation records", + Long: strings.TrimSpace( + fmt.Sprintf(`Queries all delegation records. Optionally include archived records. +Examples: + $ %[1]s query %[2]s delegation-records + $ %[1]s query %[2]s delegation-records --include-archived true +`, version.AppName, types.ModuleName), + ), + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + archiveString, err := cmd.Flags().GetString(FlagInlcudeArchived) + if err != nil { + return err + } + archiveBool, _ := strconv.ParseBool(archiveString) + + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryDelegationRecordsRequest{ + IncludeArchived: archiveBool, + } + res, err := queryClient.DelegationRecords(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + cmd.Flags().String(FlagInlcudeArchived, "", "Include archived records") + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// Queries unbonding records with an option to include archive records +func CmdQueryUnbondingRecords() *cobra.Command { + cmd := &cobra.Command{ + Use: "unbonding-records", + Short: "Queries all unbonding records", + Long: strings.TrimSpace( + fmt.Sprintf(`Queries all unbonding records. Optionally include archived records. +Example: + $ %[1]s query %[2]s unbonding-records + $ %[1]s query %[2]s unbonding-records --include-archived true +`, version.AppName, types.ModuleName), + ), + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + archiveString, err := cmd.Flags().GetString(FlagInlcudeArchived) + if err != nil { + return err + } + archiveBool, _ := strconv.ParseBool(archiveString) + + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryUnbondingRecordsRequest{ + IncludeArchived: archiveBool, + } + res, err := queryClient.UnbondingRecords(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + cmd.Flags().String(FlagInlcudeArchived, "", "Include archived records") + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// Queries a single redemption record +func CmdQueryRedemptionRecord() *cobra.Command { + cmd := &cobra.Command{ + Use: "redemption-record [epoch-number] [address]", + Short: "Queries a single redemption record", + Long: strings.TrimSpace( + fmt.Sprintf(`Queries a single redemption record +Example: + $ %s query %s redemption-record 100 strideXXX +`, version.AppName, types.ModuleName), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + unbondingRecordId, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return err + } + address := args[1] + + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryRedemptionRecordRequest{ + UnbondingRecordId: unbondingRecordId, + Address: address, + } + res, err := queryClient.RedemptionRecord(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + return cmd +} + +// Queries all redemption records with an optional address filter +func CmdQueryRedemptionRecords() *cobra.Command { + cmd := &cobra.Command{ + Use: "redemption-records", + Short: "Queries all redemption records with a optional filters", + Long: strings.TrimSpace( + fmt.Sprintf(`Queries all redemption records with an optional address or unbonding record ID filters +Examples: + $ %[1]s query %[2]s redemption-records + $ %[1]s query %[1]s redemption-records --address strideXXX + $ %[1]s query %[1]s redemption-records --unbonding-record-id strideXXX +`, version.AppName, types.ModuleName), + ), + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + address, err := cmd.Flags().GetString(FlagAddress) + if err != nil { + return err + } + unbondingRecordId, err := cmd.Flags().GetUint64(FlagUnbondingRecordId) + if err != nil { + return err + } + + if address != "" && unbondingRecordId != 0 { + return errors.New("use redemption-rate query instead of redemption-rates query to filter by both unbonding record id and address") + } + + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryRedemptionRecordsRequest{ + Address: address, + UnbondingRecordId: unbondingRecordId, + } + res, err := queryClient.RedemptionRecords(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + cmd.Flags().String(FlagAddress, "", "Filter by redeemer address") + cmd.Flags().Uint64(FlagUnbondingRecordId, 0, "Filter by unbonding record ID") + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// Queries all slash records +func CmdQuerySlashRecords() *cobra.Command { + cmd := &cobra.Command{ + Use: "slash-records", + Short: "Queries all slash records", + Long: strings.TrimSpace( + fmt.Sprintf(`Queries all slash records +Examples: + $ %s query %s slash-records +`, version.AppName, types.ModuleName), + ), + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QuerySlashRecordsRequest{} + res, err := queryClient.SlashRecords(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + return cmd +} diff --git a/x/stakedym/client/cli/tx.go b/x/stakedym/client/cli/tx.go new file mode 100644 index 0000000000..7ca8aaa301 --- /dev/null +++ b/x/stakedym/client/cli/tx.go @@ -0,0 +1,539 @@ +package cli + +import ( + "errors" + "fmt" + "strconv" + "strings" + + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" + "github.com/spf13/cobra" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +const ( + ArgIncrease = "increase" + ArgDecrease = "decrease" + RecordTypeDelegation = "delegation" + RecordTypeUnbonding = "unbonding" + RecordTypeRedemption = "redemption" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + CmdLiquidStake(), + CmdRedeemStake(), + CmdConfirmDelegation(), + CmdConfirmUndelegation(), + CmdConfirmUnbondedTokensSwept(), + CmdAdjustDelegatedBalance(), + CmdUpdateInnerRedemptionRateBounds(), + CmdResumeHostZone(), + CmdOverwriteRecord(), + CmdRefreshRedemptionRate(), + CmdSetOperatorAddress(), + ) + + return cmd +} + +// User transaction to liquid stake native tokens into stTokens +func CmdLiquidStake() *cobra.Command { + cmd := &cobra.Command{ + Use: "liquid-stake [amount]", + Short: "Liquid stakes native tokens and receives stTokens", + Long: strings.TrimSpace( + fmt.Sprintf(`Liquid stakes native tokens and receives stTokens + +Example: + $ %[1]s tx %[2]s liquid-stake 10000 +`, version.AppName, types.ModuleName), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + amount, ok := sdkmath.NewIntFromString(args[0]) + if !ok { + return errors.New("unable to parse amount") + } + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgLiquidStake( + clientCtx.GetFromAddress().String(), + amount, + ) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// User transaction to redeem stake stTokens into native tokens +func CmdRedeemStake() *cobra.Command { + cmd := &cobra.Command{ + Use: "redeem-stake [amount]", + Short: "Redeems stTokens tokens for native tokens", + Long: strings.TrimSpace( + fmt.Sprintf(`Redeems stTokens tokens for native tokens. +Native tokens will land in the redeeming address after they unbond + +Example: + $ %[1]s tx %[2]s redeem-stake 10000 +`, version.AppName, types.ModuleName), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + amount, ok := sdkmath.NewIntFromString(args[0]) + if !ok { + return errors.New("unable to parse amount") + } + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgRedeemStake( + clientCtx.GetFromAddress().String(), + amount, + ) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// Operator transaction to confirm an delegation was submitted on the host chain +func CmdConfirmDelegation() *cobra.Command { + cmd := &cobra.Command{ + Use: "confirm-delegation [record-id] [tx-hash]", + Short: "Confirms that an delegation tx was submitted", + Long: strings.TrimSpace( + fmt.Sprintf(`Confirms that a delegation tx was submitted on the host zone +The recordId corresponds with the delegation record, and the tx hash is the hash from the undelegation tx itself (used for logging purposes) + +Example: + $ %[1]s tx %[2]s confirm-delegation 100 XXXXX +`, version.AppName, types.ModuleName), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + recordId, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return err + } + txHash := args[1] + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgConfirmDelegation( + clientCtx.GetFromAddress().String(), + recordId, + txHash, + ) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// Operator transaction to confirm an undelegation was submitted on the host chain +func CmdConfirmUndelegation() *cobra.Command { + cmd := &cobra.Command{ + Use: "confirm-undelegation [record-id] [tx-hash]", + Short: "Confirms that an undelegation tx was submitted", + Long: strings.TrimSpace( + fmt.Sprintf(`Confirms that an undelegation tx was submitted on the host zone +The recordId corresponds with the unbonding record, and the tx hash is the hash from the undelegation tx itself (used for logging purposes) + +Example: + $ %[1]s tx %[2]s confirm-undelegation 100 XXXXX +`, version.AppName, types.ModuleName), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + recordId, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return err + } + txHash := args[1] + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgConfirmUndelegation( + clientCtx.GetFromAddress().String(), + recordId, + txHash, + ) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// Operator transaction to confirm unbonded tokens were transferred back to stride +func CmdConfirmUnbondedTokensSwept() *cobra.Command { + cmd := &cobra.Command{ + Use: "confirm-sweep [record-id] [tx-hash]", + Short: "Confirms that unbonded tokens were swept back to stride", + Long: strings.TrimSpace( + fmt.Sprintf(`Confirms unbonded tokens were transferred back from the host zone to stride. +The recordId corresponds with the unbonding record, and the tx hash is the hash from the ibc-transfer tx itself (used for logging purposes) + +Example: + $ %[1]s tx %[2]s confirm-sweep 100 XXXXX +`, version.AppName, types.ModuleName), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + recordId, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return err + } + txHash := args[1] + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgConfirmUnbondedTokenSweep( + clientCtx.GetFromAddress().String(), + recordId, + txHash, + ) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// Operator transaction to adjust the delegated balance after a validator was slashed +func CmdAdjustDelegatedBalance() *cobra.Command { + cmd := &cobra.Command{ + Use: "adjust-delegated-balance [increase|decrease] [delegation-offset] [validator]", + Short: "Adjust the host zone delegated balance", + Long: strings.TrimSpace( + fmt.Sprintf(`Adjust the host zone's delegated balance and logs the validator in a slash record. +Note: You must specify whether the delegation should increase or decrease + +Example: + $ %[1]s tx %[2]s adjust-delegated-balance decrease 100000 XXXXX +`, version.AppName, types.ModuleName), + ), + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + direction := args[0] + delegationOffset, ok := sdkmath.NewIntFromString(args[1]) + if !ok { + return errors.New("unable to parse delegation offset") + } + validatorAddress := args[2] + + // Make the offset negative if the intention is to decrease the amount + if direction == ArgDecrease { + delegationOffset = delegationOffset.Neg() + } else if direction != ArgIncrease { + return fmt.Errorf("invalid direction specified, must be either %s or %s", ArgIncrease, ArgDecrease) + } + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgAdjustDelegatedBalance( + clientCtx.GetFromAddress().String(), + delegationOffset, + validatorAddress, + ) + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// Adjusts the inner redemption rate bounds on the host zone +func CmdUpdateInnerRedemptionRateBounds() *cobra.Command { + cmd := &cobra.Command{ + Use: "set-redemption-rate-bounds [min-bound] [max-bound]", + Short: "Sets the inner redemption rate bounds", + Args: cobra.ExactArgs(2), + Long: strings.TrimSpace( + fmt.Sprintf(`Sets the inner redemption rate bounds on a host zone + +Example: + $ %[1]s tx %[2]s set-redemption-rate-bounds 1.10 1.20 +`, version.AppName, types.ModuleName), + ), + RunE: func(cmd *cobra.Command, args []string) (err error) { + minInnerRedemptionRate := sdk.MustNewDecFromStr(args[0]) + maxInnerRedemptionRate := sdk.MustNewDecFromStr(args[1]) + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgUpdateInnerRedemptionRateBounds( + clientCtx.GetFromAddress().String(), + minInnerRedemptionRate, + maxInnerRedemptionRate, + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// Unhalts the host zone if redemption rates were exceeded +func CmdResumeHostZone() *cobra.Command { + cmd := &cobra.Command{ + Use: "resume-host-zone", + Short: "Resumes a host zone after a halt", + Args: cobra.ExactArgs(0), + Long: strings.TrimSpace( + fmt.Sprintf(`Resumes a host zone after it was halted + +Example: + $ %[1]s tx %[2]s resume-host-zone +`, version.AppName, types.ModuleName), + ), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgResumeHostZone( + clientCtx.GetFromAddress().String(), + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// SAFE multisig overwrites record +func CmdOverwriteRecord() *cobra.Command { + cmd := &cobra.Command{ + Use: "overwrite-record [delegation|unbonding|redemption] [json-file]", + Short: "overwrites a record", + Long: strings.TrimSpace( + fmt.Sprint(`Submit an overwrite record tx. The record must be supplied via a JSON file. + +Example: +$ tx stakedym overwrite-record [delegation|unbonding|redemption] --from= + +Where file.json contains either... + +Delegation Record (recordtype=delegation) +{ + "id": "4", + "native_amount": "100", + "status": "DELEGATION_QUEUE", + "tx_hash": "C8C3CFF223CF4711E14F3E3918A3E82ED8BAA010445A4519BD0B2AFDB45897FE" +} + +Unbonding Record (recordtype=unbonding) +{ + "id": "4", + "native_amount": "100", + "st_token_amount": "94", + "UnbondingRecordStatus": "UNBONDING_QUEUE", + "unbonding_completion_time": "1705802815" + "undelegation_tx_hash": "C8C3CFF223CF4711E14F3E3918A3E82ED8BAA010445A4519BD0B2AFDB45897FE", + "unbonding_token_swap_tx_hash": "C8C3CFF223CF4711E14F3E3918A3E82ED8BAA010445A4519BD0B2AFDB45897FE" +} + +Redemption Record (recordtype=redemption) +{ + "unbonding_record_id": "4" + "native_amount": "100", + "st_token_amount": "107", + "redeemer": "stride1zlu2l3lx5tqvzspvjwsw9u0e907kelhqae3yhk" +} + + `, version.AppName)), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) (err error) { + + recordType := args[0] + recordContents := args[1] + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + switch recordType { + case RecordTypeDelegation: + return parseAndBroadcastOverwriteDelegation(clientCtx, cmd, recordContents) + case RecordTypeUnbonding: + return parseAndBroadcastOverwriteUnbonding(clientCtx, cmd, recordContents) + case RecordTypeRedemption: + return parseAndBroadcastOverwriteRedemption(clientCtx, cmd, recordContents) + default: + return fmt.Errorf("invalid record type specified, must be either %s, %s, or %s", RecordTypeDelegation, RecordTypeUnbonding, RecordTypeRedemption) + } + }, + } + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// triggers the redemption rate update +func CmdRefreshRedemptionRate() *cobra.Command { + cmd := &cobra.Command{ + Use: "trigger-update-redemption-rate", + Short: "triggers an update to the redemption rate", + Args: cobra.ExactArgs(0), + Long: strings.TrimSpace( + fmt.Sprintf(`Triggers an updated redemption rate calculation for the host zone + +Example: +$ %[1]s tx %[2]s trigger-update-redemption-rate + `, version.AppName, types.ModuleName), + ), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgRefreshRedemptionRate( + clientCtx.GetFromAddress().String(), + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// triggers the redemption rate update +func CmdSetOperatorAddress() *cobra.Command { + cmd := &cobra.Command{ + Use: "setup-operator-address [operator-address]", + Short: "sets the operator address on the host zone record", + Args: cobra.ExactArgs(1), + Long: strings.TrimSpace( + fmt.Sprintf(`Triggers an updated redemption rate calculation for the host zone + +Example: +$ %[1]s tx %[2]s setup-operator-address stride1265uqtckmd3kt7jek2pv0vrp04j0d74jj8ahq5 + `, version.AppName, types.ModuleName), + ), + RunE: func(cmd *cobra.Command, args []string) (err error) { + operatorAddress := args[0] + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgSetOperatorAddress( + clientCtx.GetFromAddress().String(), + operatorAddress, + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/stakedym/ibc_middleware.go b/x/stakedym/ibc_middleware.go new file mode 100644 index 0000000000..99b1e76b9c --- /dev/null +++ b/x/stakedym/ibc_middleware.go @@ -0,0 +1,198 @@ +package stakedym + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" + + "github.com/Stride-Labs/stride/v18/x/stakedym/keeper" +) + +var _ porttypes.Middleware = &IBCMiddleware{} + +type IBCMiddleware struct { + app porttypes.IBCModule + keeper keeper.Keeper +} + +// NewIBCMiddleware creates a new IBCMiddleware given the keeper +func NewIBCMiddleware(k keeper.Keeper, app porttypes.IBCModule) IBCMiddleware { + return IBCMiddleware{ + app: app, + keeper: k, + } +} + +// No custom logic needed for OnChanOpenInit - passes through to next middleware +func (im IBCMiddleware) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) (string, error) { + im.keeper.Logger(ctx).Info(fmt.Sprintf("OnChanOpenAck (Stakedym): portID %s, channelID %s", portID, channelID)) + return im.app.OnChanOpenInit( + ctx, + order, + connectionHops, + portID, + channelID, + channelCap, + counterparty, + version, + ) +} + +// No custom logic needed for OnChanOpenAck - passes through to next middleware +func (im IBCMiddleware) OnChanOpenAck( + ctx sdk.Context, + portID string, + channelID string, + counterpartyChannelID string, + counterpartyVersion string, +) error { + im.keeper.Logger(ctx).Info(fmt.Sprintf("OnChanOpenAck (Stakedym): portID %s, channelID %s, counterpartyChannelID %s, counterpartyVersion %s", + portID, channelID, counterpartyChannelID, counterpartyVersion)) + return im.app.OnChanOpenAck( + ctx, + portID, + channelID, + counterpartyChannelID, + counterpartyVersion, + ) +} + +// No custom logic needed for OnChanCloseConfirm - passes through to next middleware +func (im IBCMiddleware) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + im.keeper.Logger(ctx).Info(fmt.Sprintf("OnChanCloseConfirm (Stakedym): portID %s, channelID %s", portID, channelID)) + return im.app.OnChanCloseConfirm(ctx, portID, channelID) +} + +// OnAcknowledgementPacket must check the ack for outbound transfers of native tokens +// and update record keeping based on whether it succeeded +func (im IBCMiddleware) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + relayer sdk.AccAddress, +) error { + im.keeper.Logger(ctx).Info(fmt.Sprintf("OnAcknowledgementPacket (Stakedym): SourcePort %s, SourceChannel %s, DestinationPort %s, DestinationChannel %s", + packet.SourcePort, packet.SourceChannel, packet.DestinationPort, packet.DestinationChannel)) + // Handle stakedym specific logic + if err := im.keeper.OnAcknowledgementPacket(ctx, packet, acknowledgement); err != nil { + im.keeper.Logger(ctx).Error(fmt.Sprintf("ICS20 stakedym OnAckPacket failed: %s", err.Error())) + return err + } + + return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) +} + +// OnTimeoutPacket must check if an outbound transfer of native tokens timed out, +// and, if so, adjust record keeping +func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { + im.keeper.Logger(ctx).Info(fmt.Sprintf("OnTimeoutPacket (Stakedym): packet %v, relayer %v", packet, relayer)) + // Handle stakedym specific logic + if err := im.keeper.OnTimeoutPacket(ctx, packet); err != nil { + im.keeper.Logger(ctx).Error(fmt.Sprintf("ICS20 stakedym OnTimeoutPacket failed: %s", err.Error())) + return err + } + + return im.app.OnTimeoutPacket(ctx, packet, relayer) +} + +// No custom logic needed for OnChanOpenTry - passes through to next middleware +func (im IBCMiddleware) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + return im.app.OnChanOpenTry( + ctx, + order, + connectionHops, + portID, + channelID, + channelCap, + counterparty, + counterpartyVersion, + ) +} + +// No custom logic needed for OnChanOpenConfirm - passes through to next middleware +func (im IBCMiddleware) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return im.app.OnChanOpenConfirm(ctx, portID, channelID) +} + +// No custom logic needed for OnChanCloseInit - passes through to next middleware +func (im IBCMiddleware) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + return im.app.OnChanCloseInit(ctx, portID, channelID) +} + +// No custom logic needed for OnRecvPacket - passes through to next middleware +func (im IBCMiddleware) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) ibcexported.Acknowledgement { + return im.app.OnRecvPacket(ctx, packet, relayer) +} + +// Send implements the ICS4Wrapper interface +// Stakedym sits above where ICS4 traffic routes in the transfer stack +// so this should never get called +func (im IBCMiddleware) SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, +) (sequence uint64, err error) { + panic("Unexpected ICS4Wrapper route to stakedym module") +} + +// WriteAcknowledgement implements the ICS4Wrapper interface +// Stakedym sits above where ICS4 traffic routes in the transfer stack +// so this should never get called +func (im IBCMiddleware) WriteAcknowledgement( + ctx sdk.Context, + channelCap *capabilitytypes.Capability, + packet ibcexported.PacketI, + ack ibcexported.Acknowledgement, +) error { + panic("Unexpected ICS4Wrapper route to stakedym module") +} + +// GetAppVersion implements the ICS4Wrapper interface +// Stakedym sits above where ICS4 traffic routes in the transfer stack +// so this should never get called +func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + panic("Unexpected ICS4Wrapper route to stakedym module") +} diff --git a/x/stakedym/keeper/abci.go b/x/stakedym/keeper/abci.go new file mode 100644 index 0000000000..6e55a665c0 --- /dev/null +++ b/x/stakedym/keeper/abci.go @@ -0,0 +1,16 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (k Keeper) BeginBlocker(ctx sdk.Context) { + // Check invariants + + // Check redemption rate is within safety bounds + if err := k.CheckRedemptionRateExceedsBounds(ctx); err != nil { + k.Logger(ctx).Error(err.Error()) + // If not, halt the zone + k.HaltZone(ctx) + } +} diff --git a/x/stakedym/keeper/delegation.go b/x/stakedym/keeper/delegation.go new file mode 100644 index 0000000000..5efc32f0d5 --- /dev/null +++ b/x/stakedym/keeper/delegation.go @@ -0,0 +1,225 @@ +package keeper + +import ( + "fmt" + "time" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + + "github.com/Stride-Labs/stride/v18/utils" + "github.com/Stride-Labs/stride/v18/x/stakedym/types" + stakeibctypes "github.com/Stride-Labs/stride/v18/x/stakeibc/types" +) + +// Liquid stakes native tokens and returns stTokens to the user +// The staker's native tokens (which exist as an IBC denom on stride) are escrowed +// in the deposit account +// StTokens are minted at the current redemption rate +func (k Keeper) LiquidStake(ctx sdk.Context, liquidStaker string, nativeAmount sdkmath.Int) (stToken sdk.Coin, err error) { + // Get the host zone and verify it's unhalted + hostZone, err := k.GetUnhaltedHostZone(ctx) + if err != nil { + return stToken, err + } + + // Get user and deposit account addresses + liquidStakerAddress, err := sdk.AccAddressFromBech32(liquidStaker) + if err != nil { + return stToken, errorsmod.Wrapf(err, "user's address is invalid") + } + hostZoneDepositAddress, err := sdk.AccAddressFromBech32(hostZone.DepositAddress) + if err != nil { + return stToken, errorsmod.Wrapf(err, "host zone deposit address is invalid") + } + + // Check redemption rates are within safety bounds + if err := k.CheckRedemptionRateExceedsBounds(ctx); err != nil { + return stToken, err + } + + // The tokens that are sent to the protocol are denominated in the ibc hash of the native token on stride (e.g. ibc/xxx) + nativeToken := sdk.NewCoin(hostZone.NativeTokenIbcDenom, nativeAmount) + if !utils.IsIBCToken(hostZone.NativeTokenIbcDenom) { + return stToken, errorsmod.Wrapf(stakeibctypes.ErrInvalidToken, + "denom is not an IBC token (%s)", hostZone.NativeTokenIbcDenom) + } + + // Determine the amount of stTokens to mint using the redemption rate + stAmount := (sdk.NewDecFromInt(nativeAmount).Quo(hostZone.RedemptionRate)).TruncateInt() + if stAmount.IsZero() { + return stToken, errorsmod.Wrapf(stakeibctypes.ErrInsufficientLiquidStake, + "Liquid stake of %s%s would return 0 stTokens", nativeAmount.String(), hostZone.NativeTokenDenom) + } + + // Transfer the native tokens from the user to module account + if err := k.bankKeeper.SendCoins(ctx, liquidStakerAddress, hostZoneDepositAddress, sdk.NewCoins(nativeToken)); err != nil { + return stToken, errorsmod.Wrapf(err, "failed to send tokens from liquid staker %s to deposit address", liquidStaker) + } + + // Mint the stTokens and transfer them to the user + stDenom := utils.StAssetDenomFromHostZoneDenom(hostZone.NativeTokenDenom) + stToken = sdk.NewCoin(stDenom, stAmount) + if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(stToken)); err != nil { + return stToken, errorsmod.Wrapf(err, "Failed to mint stTokens") + } + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, liquidStakerAddress, sdk.NewCoins(stToken)); err != nil { + return stToken, errorsmod.Wrapf(err, "Failed to send %s from deposit address to liquid staker", stToken.String()) + } + + // Emit liquid stake event with the same schema as stakeibc + EmitSuccessfulLiquidStakeEvent(ctx, liquidStaker, hostZone, nativeAmount, stAmount) + + return stToken, nil +} + +// IBC transfers all DYM in the deposit account and sends it to the delegation account +func (k Keeper) PrepareDelegation(ctx sdk.Context, epochNumber uint64, epochDuration time.Duration) error { + k.Logger(ctx).Info(utils.LogWithHostZone(types.DymensionChainId, "Preparing delegation for epoch %d", epochNumber)) + + // Only send the transfer if the host zone isn't halted + hostZone, err := k.GetUnhaltedHostZone(ctx) + if err != nil { + return err + } + + // safety check: if any delegation records are in progress, do not allow another transfer + delegationRecords := k.GetAllActiveDelegationRecords(ctx) + for _, record := range delegationRecords { + if record.Status == types.TRANSFER_IN_PROGRESS { + return errorsmod.Wrapf(types.ErrInvariantBroken, + "cannot prepare delegation while a transfer is in progress, record ID %d", record.Id) + } + } + + // Transfer the full deposit balance which will include new liquid stakes, as well as reinvestment + depositAddress := sdk.MustAccAddressFromBech32(hostZone.DepositAddress) + nativeTokens := k.bankKeeper.GetBalance(ctx, depositAddress, hostZone.NativeTokenIbcDenom) + + // If there's nothing to delegate, exit early - no need to create a new record + if nativeTokens.Amount.IsZero() { + k.Logger(ctx).Info(utils.LogWithHostZone(types.DymensionChainId, "No new liquid stakes for epoch %d", epochNumber)) + return nil + } + + // Create a new delgation record with status TRANSFER IN PROGRESS + delegationRecord := types.DelegationRecord{ + Id: epochNumber, + NativeAmount: nativeTokens.Amount, + Status: types.TRANSFER_IN_PROGRESS, + } + err = k.SafelySetDelegationRecord(ctx, delegationRecord) + if err != nil { + return err + } + + // Timeout the transfer at the end of the epoch + timeoutTimestamp := uint64(ctx.BlockTime().Add(epochDuration).UnixNano()) + + // Transfer the native tokens to the host chain + transferMsgDepositToDelegation := transfertypes.MsgTransfer{ + SourcePort: transfertypes.PortID, + SourceChannel: hostZone.TransferChannelId, + Token: nativeTokens, + Sender: hostZone.DepositAddress, + Receiver: hostZone.DelegationAddress, + TimeoutTimestamp: timeoutTimestamp, + } + msgResponse, err := k.transferKeeper.Transfer(ctx, &transferMsgDepositToDelegation) + if err != nil { + return errorsmod.Wrapf(err, "failed to submit transfer from deposit to delegation acct in PrepareDelegation") + } + + // Store the record ID so that we can access it during the packet callback to update the record status + k.SetTransferInProgressRecordId(ctx, hostZone.TransferChannelId, msgResponse.Sequence, delegationRecord.Id) + + return nil +} + +// Confirms a delegation has completed on the host zone, increments the internal delegated balance, +// and archives the record +func (k Keeper) ConfirmDelegation(ctx sdk.Context, recordId uint64, txHash string, sender string) (err error) { + // grab unbonding record, verify record is ready to be delegated, and a hash hasn't already been posted + delegationRecord, found := k.GetDelegationRecord(ctx, recordId) + if !found { + return types.ErrDelegationRecordNotFound.Wrapf("delegation record not found for %v", recordId) + } + if delegationRecord.Status != types.DELEGATION_QUEUE { + return types.ErrDelegationRecordInvalidState.Wrapf("delegation record %v is not in the correct state", recordId) + } + if delegationRecord.TxHash != "" { + return types.ErrDelegationRecordInvalidState.Wrapf("delegation record %v already has a txHash", recordId) + } + + // note: we're intentionally not checking that the host zone is halted, because we still want to process this tx in that case + hostZone, err := k.GetHostZone(ctx) + if err != nil { + return err + } + + // verify delegation record is nonzero + if !delegationRecord.NativeAmount.IsPositive() { + return types.ErrDelegationRecordInvalidState.Wrapf("delegation record %v has non positive delegation", recordId) + } + + // update delegation record to archive it + delegationRecord.TxHash = txHash + delegationRecord.Status = types.DELEGATION_COMPLETE + k.ArchiveDelegationRecord(ctx, delegationRecord) + + // increment delegation on Host Zone + hostZone.DelegatedBalance = hostZone.DelegatedBalance.Add(delegationRecord.NativeAmount) + k.SetHostZone(ctx, hostZone) + + EmitSuccessfulConfirmDelegationEvent(ctx, recordId, delegationRecord.NativeAmount, txHash, sender) + return nil +} + +// Liquid stakes tokens in the fee account and distributes them to the fee collector +func (k Keeper) LiquidStakeAndDistributeFees(ctx sdk.Context) error { + // Get the fee address from the host zone + hostZone, err := k.GetUnhaltedHostZone(ctx) + if err != nil { + return err + } + + // Get the balance of native tokens in the fee address, if there are no tokens, no action is necessary + feeAddress := k.accountKeeper.GetModuleAddress(types.FeeAddress) + feesBalance := k.bankKeeper.GetBalance(ctx, feeAddress, hostZone.NativeTokenIbcDenom) + if feesBalance.IsZero() { + k.Logger(ctx).Info("No fees generated this epoch") + return nil + } + + // Liquid stake those native tokens + stTokens, err := k.LiquidStake(ctx, feeAddress.String(), feesBalance.Amount) + if err != nil { + return errorsmod.Wrapf(err, "unable to liquid stake fees") + } + + // Send the stTokens to the fee collector + err = k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.FeeAddress, authtypes.FeeCollectorName, sdk.NewCoins(stTokens)) + if err != nil { + return errorsmod.Wrapf(err, "unable to send liquid staked tokens to fee collector") + } + k.Logger(ctx).Info(fmt.Sprintf("Liquid staked and sent %v to fee collector", stTokens)) + + return nil +} + +// Runs prepare delegations with a cache context wrapper so revert any partial state changes +func (k Keeper) SafelyPrepareDelegation(ctx sdk.Context, epochNumber uint64, epochDuration time.Duration) error { + return utils.ApplyFuncIfNoError(ctx, func(ctx sdk.Context) error { + return k.PrepareDelegation(ctx, epochNumber, epochDuration) + }) +} + +// Liquid stakes fees with a cache context wrapper so revert any partial state changes +func (k Keeper) SafelyLiquidStakeAndDistributeFees(ctx sdk.Context) error { + return utils.ApplyFuncIfNoError(ctx, func(ctx sdk.Context) error { + return k.LiquidStakeAndDistributeFees(ctx) + }) +} diff --git a/x/stakedym/keeper/delegation_record.go b/x/stakedym/keeper/delegation_record.go new file mode 100644 index 0000000000..d766a44446 --- /dev/null +++ b/x/stakedym/keeper/delegation_record.go @@ -0,0 +1,116 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// Writes a delegation record to the active store +func (k Keeper) SetDelegationRecord(ctx sdk.Context, delegationRecord types.DelegationRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DelegationRecordsKeyPrefix) + + recordKey := types.IntKey(delegationRecord.Id) + recordBz := k.cdc.MustMarshal(&delegationRecord) + + store.Set(recordKey, recordBz) +} + +// Writes a delegation record to the archive store +func (k Keeper) SetArchivedDelegationRecord(ctx sdk.Context, delegationRecord types.DelegationRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DelegationRecordsArchiveKeyPrefix) + + recordKey := types.IntKey(delegationRecord.Id) + recordBz := k.cdc.MustMarshal(&delegationRecord) + + store.Set(recordKey, recordBz) +} + +// Writes a delegation record to the store only if a record does not already exist for that ID +func (k Keeper) SafelySetDelegationRecord(ctx sdk.Context, delegationRecord types.DelegationRecord) error { + if _, found := k.GetDelegationRecord(ctx, delegationRecord.Id); found { + return types.ErrDelegationRecordAlreadyExists.Wrapf("delegation record already exists for ID %d", delegationRecord.Id) + } + k.SetDelegationRecord(ctx, delegationRecord) + return nil +} + +// Reads a delegation record from the active store +func (k Keeper) GetDelegationRecord(ctx sdk.Context, recordId uint64) (delegationRecord types.DelegationRecord, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DelegationRecordsKeyPrefix) + + recordKey := types.IntKey(recordId) + recordBz := store.Get(recordKey) + + if len(recordBz) == 0 { + return delegationRecord, false + } + + k.cdc.MustUnmarshal(recordBz, &delegationRecord) + return delegationRecord, true +} + +// Reads a delegation record from the archive store +func (k Keeper) GetArchivedDelegationRecord(ctx sdk.Context, recordId uint64) (delegationRecord types.DelegationRecord, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DelegationRecordsArchiveKeyPrefix) + + recordKey := types.IntKey(recordId) + recordBz := store.Get(recordKey) + + if len(recordBz) == 0 { + return delegationRecord, false + } + + k.cdc.MustUnmarshal(recordBz, &delegationRecord) + return delegationRecord, true +} + +// Removes a delegation record from the active store +func (k Keeper) RemoveDelegationRecord(ctx sdk.Context, recordId uint64) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DelegationRecordsKeyPrefix) + recordKey := types.IntKey(recordId) + store.Delete(recordKey) +} + +// Removes a delegation record from the active store and writes it to the archive store, +// to preserve history +func (k Keeper) ArchiveDelegationRecord(ctx sdk.Context, delegationRecord types.DelegationRecord) { + k.RemoveDelegationRecord(ctx, delegationRecord.Id) + k.SetArchivedDelegationRecord(ctx, delegationRecord) +} + +// Returns all active delegation records +func (k Keeper) GetAllActiveDelegationRecords(ctx sdk.Context) (delegationRecords []types.DelegationRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DelegationRecordsKeyPrefix) + delegationRecordsInActiveStore := k.getAllDelegationRecords(store) + + // There should only be TRANSFER_IN_PROGRESS or DELEGATION_QUEUE records in this store + // up we'll add the check here to be safe + for _, delegationRecord := range delegationRecordsInActiveStore { + if delegationRecord.Status == types.TRANSFER_IN_PROGRESS || delegationRecord.Status == types.DELEGATION_QUEUE { + delegationRecords = append(delegationRecords, delegationRecord) + } + } + return delegationRecords +} + +// Returns all active delegation records +func (k Keeper) GetAllArchivedDelegationRecords(ctx sdk.Context) (delegationRecords []types.DelegationRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DelegationRecordsArchiveKeyPrefix) + return k.getAllDelegationRecords(store) +} + +// Returns all delegation records for a specified store (either active or archive) +func (k Keeper) getAllDelegationRecords(store prefix.Store) (delegationRecords []types.DelegationRecord) { + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + delegationRecord := types.DelegationRecord{} + k.cdc.MustUnmarshal(iterator.Value(), &delegationRecord) + delegationRecords = append(delegationRecords, delegationRecord) + } + + return delegationRecords +} diff --git a/x/stakedym/keeper/delegation_record_test.go b/x/stakedym/keeper/delegation_record_test.go new file mode 100644 index 0000000000..60161594aa --- /dev/null +++ b/x/stakedym/keeper/delegation_record_test.go @@ -0,0 +1,87 @@ +package keeper_test + +import ( + sdkmath "cosmossdk.io/math" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +func (s *KeeperTestSuite) addDelegationRecords() (delegationRecords []types.DelegationRecord) { + for i := 0; i <= 4; i++ { + delegationRecord := types.DelegationRecord{ + Id: uint64(i), + NativeAmount: sdkmath.NewInt(int64(i) * 1000), + TxHash: "hash", + } + delegationRecords = append(delegationRecords, delegationRecord) + s.App.StakedymKeeper.SetDelegationRecord(s.Ctx, delegationRecord) + } + return delegationRecords +} + +func (s *KeeperTestSuite) TestSafelySetDelegationRecord() { + // Set one record + err := s.App.StakedymKeeper.SafelySetDelegationRecord(s.Ctx, types.DelegationRecord{Id: 1}) + s.Require().NoError(err, "no error expected when setting record") + + // Attempt to set it again, it should fail + err = s.App.StakedymKeeper.SafelySetDelegationRecord(s.Ctx, types.DelegationRecord{Id: 1}) + s.Require().ErrorContains(err, "delegation record already exists") + + // Set a new ID, it should succeed + err = s.App.StakedymKeeper.SafelySetDelegationRecord(s.Ctx, types.DelegationRecord{Id: 2}) + s.Require().NoError(err, "no error expected when setting new ID") +} + +func (s *KeeperTestSuite) TestGetDelegationRecord() { + delegationRecords := s.addDelegationRecords() + + for i := 0; i < len(delegationRecords); i++ { + expectedRecord := delegationRecords[i] + recordId := expectedRecord.Id + + actualRecord, found := s.App.StakedymKeeper.GetDelegationRecord(s.Ctx, recordId) + s.Require().True(found, "delegation record %d should have been found", i) + s.Require().Equal(expectedRecord, actualRecord) + } +} + +// Tests ArchiveDelegationRecord and GetAllArchivedDelegationRecords +func (s *KeeperTestSuite) TestArchiveDelegationRecord() { + delegationRecords := s.addDelegationRecords() + + for removedIndex := 0; removedIndex < len(delegationRecords); removedIndex++ { + // Archive from removed index + removedRecord := delegationRecords[removedIndex] + s.App.StakedymKeeper.ArchiveDelegationRecord(s.Ctx, removedRecord) + + // Confirm removed from active + _, found := s.App.StakedymKeeper.GetDelegationRecord(s.Ctx, removedRecord.Id) + s.Require().False(found, "record %d should have been removed", removedRecord.Id) + + // Confirm placed in archive + _, found = s.App.StakedymKeeper.GetArchivedDelegationRecord(s.Ctx, removedRecord.Id) + s.Require().True(found, "record %d should have been moved to the archive store", removedRecord.Id) + + // Check all other records are still there + for checkedIndex := removedIndex + 1; checkedIndex < len(delegationRecords); checkedIndex++ { + checkedId := delegationRecords[checkedIndex].Id + _, found := s.App.StakedymKeeper.GetDelegationRecord(s.Ctx, checkedId) + s.Require().True(found, "record %d should still be here after %d removal", checkedId, removedRecord.Id) + } + } + + // Check that they were all archived + archivedRecords := s.App.StakedymKeeper.GetAllArchivedDelegationRecords(s.Ctx) + for i := 0; i < len(delegationRecords); i++ { + expectedRecordId := delegationRecords[i].Id + s.Require().Equal(expectedRecordId, archivedRecords[i].Id, "archived record %d", i) + } +} + +func (s *KeeperTestSuite) TestGetAllActiveDelegationRecords() { + expectedRecords := s.addDelegationRecords() + actualRecords := s.App.StakedymKeeper.GetAllActiveDelegationRecords(s.Ctx) + s.Require().Equal(len(expectedRecords), len(actualRecords), "number of delegation records") + s.Require().Equal(expectedRecords, actualRecords) +} diff --git a/x/stakedym/keeper/delegation_test.go b/x/stakedym/keeper/delegation_test.go new file mode 100644 index 0000000000..ee80fd8fb8 --- /dev/null +++ b/x/stakedym/keeper/delegation_test.go @@ -0,0 +1,550 @@ +package keeper_test + +import ( + "time" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +var InitialDelegation = sdkmath.NewInt(1_000_000) + +type LiquidStakeTestCase struct { + liquidStakeAmount sdkmath.Int + expectedStAmount sdkmath.Int + stakerAddress sdk.AccAddress + depositAddress sdk.AccAddress +} + +// ---------------------------------------------------- +// LiquidStake +// ---------------------------------------------------- + +// Helper function to mock relevant state before testing a liquid stake +func (s *KeeperTestSuite) SetupTestLiquidStake( + redemptionRate sdk.Dec, + liquidStakeAmount, + expectedStAmount sdkmath.Int, +) LiquidStakeTestCase { + // Create relevant addresses + stakerAddress := s.TestAccs[0] + depositAddress := s.TestAccs[1] + + // Create a host zone with relevant denom's and addresses + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + ChainId: HostChainId, + NativeTokenDenom: HostNativeDenom, + NativeTokenIbcDenom: HostIBCDenom, + DepositAddress: depositAddress.String(), + RedemptionRate: redemptionRate, + MinRedemptionRate: redemptionRate.Sub(sdk.MustNewDecFromStr("0.2")), + MinInnerRedemptionRate: redemptionRate.Sub(sdk.MustNewDecFromStr("0.1")), + MaxInnerRedemptionRate: redemptionRate.Add(sdk.MustNewDecFromStr("0.1")), + MaxRedemptionRate: redemptionRate.Add(sdk.MustNewDecFromStr("0.2")), + }) + + // Fund the staker + liquidStakeToken := sdk.NewCoin(HostIBCDenom, liquidStakeAmount) + s.FundAccount(stakerAddress, liquidStakeToken) + + return LiquidStakeTestCase{ + liquidStakeAmount: liquidStakeAmount, + expectedStAmount: expectedStAmount, + stakerAddress: stakerAddress, + depositAddress: depositAddress, + } +} + +// Helper function to setup the state with default values +// (useful when testing error cases) +func (s *KeeperTestSuite) DefaultSetupTestLiquidStake() LiquidStakeTestCase { + redemptionRate := sdk.MustNewDecFromStr("1.0") + liquidStakeAmount := sdkmath.NewInt(1000) + stAmount := sdkmath.NewInt(1000) + return s.SetupTestLiquidStake(redemptionRate, liquidStakeAmount, stAmount) +} + +// Helper function to confirm balances after a successful liquid stake +func (s *KeeperTestSuite) ConfirmLiquidStakeTokenTransfer(tc LiquidStakeTestCase) { + zeroNativeTokens := sdk.NewCoin(HostIBCDenom, sdk.ZeroInt()) + liquidStakedNativeTokens := sdk.NewCoin(HostIBCDenom, tc.liquidStakeAmount) + + zeroStTokens := sdk.NewCoin(StDenom, sdk.ZeroInt()) + liquidStakedStTokens := sdk.NewCoin(StDenom, tc.expectedStAmount) + + // Confirm native tokens were escrowed + // Staker balance should have decreased to zero + // Deposit balance should have increased by liquid stake amount + stakerNativeBalance := s.App.BankKeeper.GetBalance(s.Ctx, tc.stakerAddress, HostIBCDenom) + s.CompareCoins(zeroNativeTokens, stakerNativeBalance, "staker native balance") + + depositNativeBalance := s.App.BankKeeper.GetBalance(s.Ctx, tc.depositAddress, HostIBCDenom) + s.CompareCoins(liquidStakedNativeTokens, depositNativeBalance, "deposit native balance") + + // Confirm stTokens were minted to the user + // Staker balance should increase by the liquid stake amount + // Deposit balance should still be zero + stakerStBalance := s.App.BankKeeper.GetBalance(s.Ctx, tc.stakerAddress, StDenom) + s.CompareCoins(liquidStakedStTokens, stakerStBalance, "staker stToken balance") + + depositStBalance := s.App.BankKeeper.GetBalance(s.Ctx, tc.depositAddress, StDenom) + s.CompareCoins(zeroStTokens, depositStBalance, "deposit native balance") +} + +func (s *KeeperTestSuite) TestLiquidStake_Successful() { + // Test liquid stake across different redemption rates + testCases := []struct { + name string + redemptionRate sdk.Dec + liquidStakeAmount sdkmath.Int + expectedStAmount sdkmath.Int + }{ + { + // Redemption Rate of 1: + // 1000 native -> 1000 stTokens + name: "redemption rate of 1", + redemptionRate: sdk.MustNewDecFromStr("1.0"), + liquidStakeAmount: sdkmath.NewInt(1000), + expectedStAmount: sdkmath.NewInt(1000), + }, + { + // Redemption Rate of 2: + // 1000 native -> 500 stTokens + name: "redemption rate of 2", + redemptionRate: sdk.MustNewDecFromStr("2.0"), + liquidStakeAmount: sdkmath.NewInt(1000), + expectedStAmount: sdkmath.NewInt(500), + }, + { + // Redemption Rate of 0.5: + // 1000 native -> 2000 stTokens + name: "redemption rate of 0.5", + redemptionRate: sdk.MustNewDecFromStr("0.5"), + liquidStakeAmount: sdkmath.NewInt(1000), + expectedStAmount: sdkmath.NewInt(2000), + }, + { + // Redemption Rate of 1.1: + // 333 native -> 302.72 (302) stTokens + name: "int truncation", + redemptionRate: sdk.MustNewDecFromStr("1.1"), + liquidStakeAmount: sdkmath.NewInt(333), + expectedStAmount: sdkmath.NewInt(302), + }, + } + + for _, testCase := range testCases { + s.Run(testCase.name, func() { + s.SetupTest() // reset state + tc := s.SetupTestLiquidStake(testCase.redemptionRate, testCase.liquidStakeAmount, testCase.expectedStAmount) + + // Confirm liquid stake succeeded + stTokenResponse, err := s.App.StakedymKeeper.LiquidStake(s.Ctx, tc.stakerAddress.String(), tc.liquidStakeAmount) + s.Require().NoError(err, "no error expected during liquid stake") + + // Confirm the stToken from the response matches expectations + s.Require().Equal(StDenom, stTokenResponse.Denom, "st token denom in liquid stake response") + s.Require().Equal(tc.expectedStAmount.Int64(), stTokenResponse.Amount.Int64(), + "st token amount in liquid stake response") + + // Confirm the native token escrow and stToken mint succeeded + s.ConfirmLiquidStakeTokenTransfer(tc) + }) + } +} + +func (s *KeeperTestSuite) TestLiquidStake_HostZoneHalted() { + tc := s.DefaultSetupTestLiquidStake() + + // Halt the host zone so the liquid stake fails + hostZone := s.MustGetHostZone() + hostZone.Halted = true + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + _, err := s.App.StakedymKeeper.LiquidStake(s.Ctx, tc.stakerAddress.String(), tc.liquidStakeAmount) + s.Require().ErrorContains(err, "host zone is halted") +} + +func (s *KeeperTestSuite) TestLiquidStake_InvalidAddresse() { + tc := s.DefaultSetupTestLiquidStake() + + // Pass an invalid staker address and confirm it fails + _, err := s.App.StakedymKeeper.LiquidStake(s.Ctx, "invalid_address", tc.liquidStakeAmount) + s.Require().ErrorContains(err, "user's address is invalid") + + // Set an invalid deposit address and confirm it fails + hostZone := s.MustGetHostZone() + hostZone.DepositAddress = "invalid_address" + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + _, err = s.App.StakedymKeeper.LiquidStake(s.Ctx, tc.stakerAddress.String(), tc.liquidStakeAmount) + s.Require().ErrorContains(err, "host zone deposit address is invalid") +} + +func (s *KeeperTestSuite) TestLiquidStake_InvalidRedemptionRate() { + tc := s.DefaultSetupTestLiquidStake() + + // Update the redemption rate so it exceeds the bounds + hostZone := s.MustGetHostZone() + hostZone.RedemptionRate = hostZone.MaxInnerRedemptionRate.Add(sdk.MustNewDecFromStr("0.01")) + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + _, err := s.App.StakedymKeeper.LiquidStake(s.Ctx, tc.stakerAddress.String(), tc.liquidStakeAmount) + s.Require().ErrorContains(err, "redemption rate outside inner safety bounds") +} + +func (s *KeeperTestSuite) TestLiquidStake_InvalidIBCDenom() { + tc := s.DefaultSetupTestLiquidStake() + + // Set an invalid IBC denom on the host so the liquid stake fails + hostZone := s.MustGetHostZone() + hostZone.NativeTokenIbcDenom = "non-ibc-denom" + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + _, err := s.App.StakedymKeeper.LiquidStake(s.Ctx, tc.stakerAddress.String(), tc.liquidStakeAmount) + s.Require().ErrorContains(err, "denom is not an IBC token") +} + +func (s *KeeperTestSuite) TestLiquidStake_InsufficientLiquidStake() { + // Adjust redemption rate so that a small liquid stake will result in 0 stTokens + // stTokens = 1(amount) / 1.1(RR) = rounds down to 0 + redemptionRate := sdk.MustNewDecFromStr("1.1") + liquidStakeAmount := sdkmath.NewInt(1) + expectedStAmount := sdkmath.ZeroInt() + tc := s.SetupTestLiquidStake(redemptionRate, liquidStakeAmount, expectedStAmount) + + _, err := s.App.StakedymKeeper.LiquidStake(s.Ctx, tc.stakerAddress.String(), tc.liquidStakeAmount) + s.Require().ErrorContains(err, "Liquid staked amount is too small") +} + +func (s *KeeperTestSuite) TestLiquidStake_InsufficientFunds() { + // Attempt to liquid stake more tokens than the staker has available + tc := s.DefaultSetupTestLiquidStake() + + excessiveLiquidStakeAmount := sdkmath.NewInt(10000000000) + _, err := s.App.StakedymKeeper.LiquidStake(s.Ctx, tc.stakerAddress.String(), excessiveLiquidStakeAmount) + s.Require().ErrorContains(err, "failed to send tokens from liquid staker") + s.Require().ErrorContains(err, "insufficient funds") +} + +// ---------------------------------------------------- +// PrepareDelegation +// ---------------------------------------------------- + +func (s *KeeperTestSuite) TestPrepareDelegation() { + s.CreateTransferChannel(HostChainId) + + // Only the deposit address must be valid + depositAddress := s.TestAccs[0] + delegationAddress := "dymXXX" + + // We must use a valid IBC denom for this test + nativeIbcDenom := s.CreateAndStoreIBCDenom(HostNativeDenom) + + // Create the host zone with relevant addresses and an IBC denom + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + DepositAddress: depositAddress.String(), + DelegationAddress: delegationAddress, + NativeTokenIbcDenom: nativeIbcDenom, + TransferChannelId: ibctesting.FirstChannelID, + }) + + // Fund the deposit account with tokens that will be transferred + depositAccountBalance := sdkmath.NewInt(1_000_000) + nativeTokensInDeposit := sdk.NewCoin(nativeIbcDenom, depositAccountBalance) + s.FundAccount(depositAddress, nativeTokensInDeposit) + + // Get next sequence number to confirm IBC transfer + startSequence := s.MustGetNextSequenceNumber(transfertypes.PortID, ibctesting.FirstChannelID) + + // submit prepare delegation + epochNumber := uint64(1) + epochDuration := time.Hour * 24 + err := s.App.StakedymKeeper.PrepareDelegation(s.Ctx, epochNumber, epochDuration) + s.Require().NoError(err, "no error expected when preparing delegation") + + // check that a delegation record was created + delegationRecords := s.App.StakedymKeeper.GetAllActiveDelegationRecords(s.Ctx) + s.Require().Equal(1, len(delegationRecords), "number of delegation records") + + // check that the delegation record has the correct id, status, and amount + delegationRecord := delegationRecords[0] + s.Require().Equal(epochNumber, delegationRecord.Id, "delegation record epoch number") + s.Require().Equal(types.TRANSFER_IN_PROGRESS, delegationRecord.Status, "delegation record status") + s.Require().Equal(depositAccountBalance, delegationRecord.NativeAmount, "delegation record amount") + + // check that the transfer in progress record was created + transferInProgressRecordId, found := s.App.StakedymKeeper.GetTransferInProgressRecordId(s.Ctx, ibctesting.FirstChannelID, startSequence) + s.Require().True(found, "transfer in progress record should have been found") + s.Require().Equal(epochNumber, transferInProgressRecordId, "transfer in progress record ID") + + // check that the tokens were burned and the sequence number was incremented + // (indicating that the transfer was submitted) + endSequence := s.MustGetNextSequenceNumber(transfertypes.PortID, ibctesting.FirstChannelID) + s.Require().Equal(startSequence+1, endSequence, "sequence number should have incremented") + + nativeTokenSupply := s.App.BankKeeper.GetSupply(s.Ctx, nativeIbcDenom) + s.Require().Zero(nativeTokenSupply.Amount.Int64(), "ibc tokens should have been burned") + + // Check that the deposit account is empty + depositAccountBalance = s.App.BankKeeper.GetBalance(s.Ctx, depositAddress, nativeIbcDenom).Amount + s.Require().Zero(depositAccountBalance.Int64(), "deposit account balance should be empty") + + // Check that if we ran this again immediately, it would error because there is a transfer record in progress already + err = s.App.StakedymKeeper.PrepareDelegation(s.Ctx, epochNumber+1, epochDuration) + s.Require().ErrorContains(err, "cannot prepare delegation while a transfer is in progress") + + // Remove the record and try to run it again + s.App.StakedymKeeper.ArchiveDelegationRecord(s.Ctx, delegationRecord) + err = s.App.StakedymKeeper.PrepareDelegation(s.Ctx, epochNumber+1, epochDuration) + s.Require().NoError(err, "no error expected when preparing delegation again") + + // It should not create a new record since there is nothing to delegate + delegationRecords = s.App.StakedymKeeper.GetAllActiveDelegationRecords(s.Ctx) + s.Require().Equal(0, len(delegationRecords), "there should be no delegation records") + + // Halt zone + s.App.StakedymKeeper.HaltZone(s.Ctx) + err = s.App.StakedymKeeper.PrepareDelegation(s.Ctx, epochNumber, epochDuration) + s.Require().ErrorContains(err, "host zone is halted") +} + +// ---------------------------------------------------- +// ConfirmDelegation +// ---------------------------------------------------- + +func (s *KeeperTestSuite) GetDefaultDelegationRecords() []types.DelegationRecord { + delegationRecords := []types.DelegationRecord{ + { + Id: 1, + NativeAmount: sdk.NewInt(1000), + Status: types.TRANSFER_IN_PROGRESS, + TxHash: "", + }, + { + Id: 6, // out of order to make sure this won't break anything + NativeAmount: sdk.NewInt(6000), + Status: types.DELEGATION_QUEUE, // to be set + TxHash: "", + }, + { + Id: 5, // out of order to make sure this won't break anything + NativeAmount: sdk.NewInt(5000), + Status: types.TRANSFER_IN_PROGRESS, + TxHash: "", + }, + { + Id: 3, + NativeAmount: sdk.NewInt(3000), + Status: types.TRANSFER_FAILED, + TxHash: "", + }, + { + Id: 2, + NativeAmount: sdk.NewInt(2000), + Status: types.DELEGATION_QUEUE, // to be set + TxHash: "", + }, + { + Id: 7, + NativeAmount: sdk.NewInt(7000), + Status: types.TRANSFER_FAILED, + TxHash: ValidTxHashDefault, + }, + } + + return delegationRecords +} + +// Helper function to setup delegation records, returns a list of records +func (s *KeeperTestSuite) SetupDelegationRecords() { + // Set Delegation Records + delegationRecords := s.GetDefaultDelegationRecords() + // loop through and set each record + for _, delegationRecord := range delegationRecords { + s.App.StakedymKeeper.SetDelegationRecord(s.Ctx, delegationRecord) + } + + // Set HostZone + hostZone := s.initializeHostZone() + hostZone.DelegatedBalance = InitialDelegation + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) +} + +func (s *KeeperTestSuite) VerifyDelegationRecords(verifyIdentical bool, archiveIds ...uint64) { + defaultDelegationRecords := s.GetDefaultDelegationRecords() + + hostZone := s.MustGetHostZone() + + for _, defaultDelegationRecord := range defaultDelegationRecords { + // check if record should be archived + shouldBeArchived := false + for _, archiveId := range archiveIds { + if defaultDelegationRecord.Id == archiveId { + shouldBeArchived = true + break + } + } + + // grab relevant record in store + loadedDelegationRecord := types.DelegationRecord{} + found := false + if shouldBeArchived { + loadedDelegationRecord, found = s.App.StakedymKeeper.GetArchivedDelegationRecord(s.Ctx, defaultDelegationRecord.Id) + } else { + loadedDelegationRecord, found = s.App.StakedymKeeper.GetDelegationRecord(s.Ctx, defaultDelegationRecord.Id) + } + s.Require().True(found) + // verify record is correct + s.Require().Equal(defaultDelegationRecord.Id, loadedDelegationRecord.Id) + s.Require().Equal(defaultDelegationRecord.NativeAmount, loadedDelegationRecord.NativeAmount) + + // Verify status and txHash are correct, if needed + if (defaultDelegationRecord.Status == types.TRANSFER_FAILED) || + (defaultDelegationRecord.Status == types.TRANSFER_IN_PROGRESS) || + verifyIdentical { + s.Require().Equal(defaultDelegationRecord.Status, loadedDelegationRecord.Status) + s.Require().Equal(defaultDelegationRecord.TxHash, loadedDelegationRecord.TxHash) + } + + // if nothing should have changed, verify that host zone balance is unmodified + if verifyIdentical { + // verify hostZone delegated balance is same as initial delegation + s.Require().Equal(InitialDelegation.Int64(), hostZone.DelegatedBalance.Int64(), "hostZone delegated balance should not have changed") + } + } +} + +func (s *KeeperTestSuite) TestConfirmDelegation_Successful() { + s.SetupDelegationRecords() + + // we're halting the zone to test that the tx works even when the host zone is halted + s.App.StakedymKeeper.HaltZone(s.Ctx) + + // try setting valid delegation queue + err := s.App.StakedymKeeper.ConfirmDelegation(s.Ctx, 6, ValidTxHashNew, ValidOperator) + s.Require().NoError(err) + s.VerifyDelegationRecords(false, 6) + + // verify record 6 modified + loadedDelegationRecord, found := s.App.StakedymKeeper.GetArchivedDelegationRecord(s.Ctx, 6) + s.Require().True(found) + s.Require().Equal(types.DELEGATION_COMPLETE, loadedDelegationRecord.Status, "delegation record should be updated to status DELEGATION_ARCHIVE") + s.Require().Equal(ValidTxHashNew, loadedDelegationRecord.TxHash, "delegation record should be updated with txHash") + + // verify hostZone delegated balance is same as initial delegation + 6000 + hostZone := s.MustGetHostZone() + s.Require().Equal(InitialDelegation.Int64()+6000, hostZone.DelegatedBalance.Int64(), "hostZone delegated balance should have increased by 6000") +} + +func (s *KeeperTestSuite) TestConfirmDelegation_DelegationZero() { + s.SetupDelegationRecords() + + // try setting delegation queue with zero delegation + delegationRecord, found := s.App.StakedymKeeper.GetDelegationRecord(s.Ctx, 6) + s.Require().True(found) + delegationRecord.NativeAmount = sdk.NewInt(0) + s.App.StakedymKeeper.SetDelegationRecord(s.Ctx, delegationRecord) + err := s.App.StakedymKeeper.ConfirmDelegation(s.Ctx, 6, ValidTxHashNew, ValidOperator) + s.Require().ErrorIs(err, types.ErrDelegationRecordInvalidState, "not allowed to confirm zero delegation") +} + +func (s *KeeperTestSuite) TestConfirmDelegation_DelegationNegative() { + s.SetupDelegationRecords() + + // try setting delegation queue with negative delegation + delegationRecord, found := s.App.StakedymKeeper.GetDelegationRecord(s.Ctx, 6) + s.Require().True(found) + delegationRecord.NativeAmount = sdk.NewInt(-10) + s.App.StakedymKeeper.SetDelegationRecord(s.Ctx, delegationRecord) + err := s.App.StakedymKeeper.ConfirmDelegation(s.Ctx, 6, ValidTxHashNew, ValidOperator) + s.Require().ErrorIs(err, types.ErrDelegationRecordInvalidState, "not allowed to confirm negative delegation") +} + +func (s *KeeperTestSuite) TestConfirmDelegation_RecordDoesntExist() { + s.SetupDelegationRecords() + + // try setting invalid record id + err := s.App.StakedymKeeper.ConfirmDelegation(s.Ctx, 15, ValidTxHashNew, ValidOperator) + s.Require().ErrorIs(err, types.ErrDelegationRecordNotFound) + + // verify delegation records haven't changed + s.VerifyDelegationRecords(true) +} + +func (s *KeeperTestSuite) TestConfirmDelegation_RecordIncorrectState() { + s.SetupDelegationRecords() + + // first verify records in wrong status + ids := []uint64{1, 3, 5, 7} + for _, id := range ids { + err := s.App.StakedymKeeper.ConfirmDelegation(s.Ctx, id, ValidTxHashNew, ValidOperator) + s.Require().ErrorIs(err, types.ErrDelegationRecordInvalidState) + // verify delegation records haven't changed + s.VerifyDelegationRecords(true) + } +} + +// ---------------------------------------------------- +// LiquidStakeAndDistributeFees +// ---------------------------------------------------- + +func (s *KeeperTestSuite) TestLiquidStakeAndDistributeFees() { + // Create relevant addresses + depositAddress := s.TestAccs[0] + feeAddress := s.App.AccountKeeper.GetModuleAddress(types.FeeAddress) + + // Liquid stake 1000 with a RR of 2, should return 500 tokens + liquidStakeAmount := sdkmath.NewInt(1000) + redemptionRate := sdk.NewDec(2) + expectedStTokens := sdkmath.NewInt(500) + + // Create a host zone with relevant denom's and addresses + hostZone := types.HostZone{ + ChainId: HostChainId, + NativeTokenDenom: HostNativeDenom, + NativeTokenIbcDenom: HostIBCDenom, + DepositAddress: depositAddress.String(), + RedemptionRate: redemptionRate, + MinRedemptionRate: redemptionRate.Sub(sdk.MustNewDecFromStr("0.2")), + MinInnerRedemptionRate: redemptionRate.Sub(sdk.MustNewDecFromStr("0.1")), + MaxInnerRedemptionRate: redemptionRate.Add(sdk.MustNewDecFromStr("0.1")), + MaxRedemptionRate: redemptionRate.Add(sdk.MustNewDecFromStr("0.2")), + } + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + // Fund the fee address with native tokens + liquidStakeToken := sdk.NewCoin(HostIBCDenom, liquidStakeAmount) + s.FundAccount(feeAddress, liquidStakeToken) + + // Call liquid stake and distribute + err := s.App.StakedymKeeper.LiquidStakeAndDistributeFees(s.Ctx) + s.Require().NoError(err, "no error expected when liquid staking fee tokens") + + // Confirm stTokens were sent to the fee collector + feeCollectorAddress := s.App.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName) + feeCollectorBalance := s.App.BankKeeper.GetBalance(s.Ctx, feeCollectorAddress, StDenom) + s.Require().Equal(expectedStTokens.Int64(), feeCollectorBalance.Amount.Int64(), + "fee collector should have received sttokens") + + // Attempt to liquid stake again when there are no more rewards, it should succeed but do nothing + err = s.App.StakedymKeeper.LiquidStakeAndDistributeFees(s.Ctx) + s.Require().NoError(err, "no error expected when liquid staking again") + + feeCollectorBalance = s.App.BankKeeper.GetBalance(s.Ctx, feeCollectorAddress, StDenom) + s.Require().Equal(expectedStTokens.Int64(), feeCollectorBalance.Amount.Int64(), + "fee collector should not have changed") + + // Test that if the host zone is halted, it will error + haltedHostZone := hostZone + haltedHostZone.Halted = true + s.App.StakedymKeeper.SetHostZone(s.Ctx, haltedHostZone) + + err = s.App.StakedymKeeper.LiquidStakeAndDistributeFees(s.Ctx) + s.Require().ErrorContains(err, "host zone is halted") +} diff --git a/x/stakedym/keeper/events.go b/x/stakedym/keeper/events.go new file mode 100644 index 0000000000..d700dfebc0 --- /dev/null +++ b/x/stakedym/keeper/events.go @@ -0,0 +1,96 @@ +package keeper + +import ( + "strconv" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// Emits a successful liquid stake event, and displays metadata such as the stToken amount +func EmitSuccessfulLiquidStakeEvent(ctx sdk.Context, staker string, hostZone types.HostZone, nativeAmount, stAmount sdkmath.Int) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeLiquidStakeRequest, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeKeyLiquidStaker, staker), + sdk.NewAttribute(types.AttributeKeyHostZone, hostZone.ChainId), + sdk.NewAttribute(types.AttributeKeyNativeBaseDenom, hostZone.NativeTokenDenom), + sdk.NewAttribute(types.AttributeKeyNativeIBCDenom, hostZone.NativeTokenIbcDenom), + sdk.NewAttribute(types.AttributeKeyNativeAmount, nativeAmount.String()), + sdk.NewAttribute(types.AttributeKeyStTokenAmount, stAmount.String()), + ), + ) +} + +// Emits a successful redeem stake event, and displays metadata such as the native amount +func EmitSuccessfulRedeemStakeEvent(ctx sdk.Context, staker string, hostZone types.HostZone, nativeAmount, stAmount sdkmath.Int) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeRedeemStakeRequest, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeKeyRedeemer, staker), + sdk.NewAttribute(types.AttributeKeyHostZone, hostZone.ChainId), + sdk.NewAttribute(types.AttributeKeyNativeBaseDenom, hostZone.NativeTokenDenom), + sdk.NewAttribute(types.AttributeKeyNativeIBCDenom, hostZone.NativeTokenIbcDenom), + sdk.NewAttribute(types.AttributeKeyNativeAmount, nativeAmount.String()), + sdk.NewAttribute(types.AttributeKeyStTokenAmount, stAmount.String()), + ), + ) +} + +// Emits an event indicated the delegation record is correctly marked as done +func EmitSuccessfulConfirmDelegationEvent(ctx sdk.Context, recordId uint64, delegationAmount sdkmath.Int, txHash string, sender string) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeConfirmDelegationResponse, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeRecordId, strconv.FormatUint(recordId, 10)), + sdk.NewAttribute(types.AttributeDelegationNativeAmount, delegationAmount.String()), + sdk.NewAttribute(types.AttributeTxHash, txHash), + sdk.NewAttribute(types.AttributeSender, sender), + ), + ) +} + +// Emits an event indicated the undelegation record is correctly marked as unbonding_in_progress +func EmitSuccessfulConfirmUndelegationEvent(ctx sdk.Context, recordId uint64, nativeAmount sdkmath.Int, txHash string, sender string) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeConfirmUndelegation, + sdk.NewAttribute(sdk.AttributeKeySender, sender), + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeRecordId, strconv.FormatUint(recordId, 10)), + sdk.NewAttribute(types.AttributeUndelegationNativeAmount, nativeAmount.String()), + sdk.NewAttribute(types.AttributeTxHash, txHash), + sdk.NewAttribute(types.AttributeSender, sender), + ), + ) +} + +// Emits an event indicated the unbonding record is correctly marked as claimable +func EmitSuccessfulConfirmUnbondedTokenSweepEvent(ctx sdk.Context, recordId uint64, nativeAmount sdkmath.Int, txHash string, sender string) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeConfirmUnbondedTokenSweep, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeRecordId, strconv.FormatUint(recordId, 10)), + sdk.NewAttribute(types.AttributeUndelegationNativeAmount, nativeAmount.String()), + sdk.NewAttribute(types.AttributeTxHash, txHash), + sdk.NewAttribute(types.AttributeSender, sender), + ), + ) +} + +// Emits an event indicating a zone was halted +func EmitHaltZoneEvent(ctx sdk.Context, hostZone types.HostZone) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeHostZoneHalt, + sdk.NewAttribute(types.AttributeKeyHostZone, hostZone.ChainId), + sdk.NewAttribute(types.AttributeKeyRedemptionRate, hostZone.RedemptionRate.String()), + ), + ) +} diff --git a/x/stakedym/keeper/genesis.go b/x/stakedym/keeper/genesis.go new file mode 100644 index 0000000000..b0f11c53cc --- /dev/null +++ b/x/stakedym/keeper/genesis.go @@ -0,0 +1,57 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// Initializes the genesis state in the store +func (k Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { + // Validate that all required fields are specified + if err := genState.Validate(); err != nil { + panic(err) + } + + // Create fee module account (calling GetModuleAccount will set it for the first time) + k.accountKeeper.GetModuleAccount(ctx, types.FeeAddress) + + // Set the main host zone config + k.SetHostZone(ctx, genState.HostZone) + + // Set all the records to their respective stores + for _, delegationRecord := range genState.DelegationRecords { + k.SetDelegationRecord(ctx, delegationRecord) + } + for _, unbondingRecord := range genState.UnbondingRecords { + k.SetUnbondingRecord(ctx, unbondingRecord) + } + for _, redemptionRecord := range genState.RedemptionRecords { + k.SetRedemptionRecord(ctx, redemptionRecord) + } + for _, slashRecord := range genState.SlashRecords { + k.SetSlashRecord(ctx, slashRecord) + } + for _, transfer := range genState.TransferInProgressRecordIds { + k.SetTransferInProgressRecordId(ctx, transfer.ChannelId, transfer.Sequence, transfer.RecordId) + } +} + +// Exports the current state +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + genesis := types.DefaultGenesis() + + hostZone, err := k.GetHostZone(ctx) + if err != nil { + panic(err) + } + + genesis.HostZone = hostZone + genesis.DelegationRecords = append(k.GetAllActiveDelegationRecords(ctx), k.GetAllArchivedDelegationRecords(ctx)...) + genesis.UnbondingRecords = append(k.GetAllActiveUnbondingRecords(ctx), k.GetAllArchivedUnbondingRecords(ctx)...) + genesis.RedemptionRecords = k.GetAllRedemptionRecords(ctx) + genesis.SlashRecords = k.GetAllSlashRecords(ctx) + genesis.TransferInProgressRecordIds = k.GetAllTransferInProgressId(ctx) + + return genesis +} diff --git a/x/stakedym/keeper/grpc_query.go b/x/stakedym/keeper/grpc_query.go new file mode 100644 index 0000000000..06b5d1f20c --- /dev/null +++ b/x/stakedym/keeper/grpc_query.go @@ -0,0 +1,181 @@ +package keeper + +import ( + "context" + "time" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +var _ types.QueryServer = Keeper{} + +// Queries the host zone struct +func (k Keeper) HostZone(c context.Context, req *types.QueryHostZoneRequest) (*types.QueryHostZoneResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(c) + + hostZone, err := k.GetHostZone(ctx) + if err != nil { + return &types.QueryHostZoneResponse{}, err + } + + return &types.QueryHostZoneResponse{HostZone: &hostZone}, nil +} + +// Queries the delegation records with an optional to include archived records +func (k Keeper) DelegationRecords(c context.Context, req *types.QueryDelegationRecordsRequest) (*types.QueryDelegationRecordsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(c) + + delegationRecords := k.GetAllActiveDelegationRecords(ctx) + if req.IncludeArchived { + delegationRecords = append(delegationRecords, k.GetAllArchivedDelegationRecords(ctx)...) + } + + return &types.QueryDelegationRecordsResponse{DelegationRecords: delegationRecords}, nil +} + +// Queries the unbonding records with an optional to include archived records +func (k Keeper) UnbondingRecords(c context.Context, req *types.QueryUnbondingRecordsRequest) (*types.QueryUnbondingRecordsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(c) + + unbondingRecords := k.GetAllActiveUnbondingRecords(ctx) + if req.IncludeArchived { + unbondingRecords = append(unbondingRecords, k.GetAllArchivedUnbondingRecords(ctx)...) + } + + return &types.QueryUnbondingRecordsResponse{UnbondingRecords: unbondingRecords}, nil +} + +// Queries a single user redemption record +func (k Keeper) RedemptionRecord(c context.Context, req *types.QueryRedemptionRecordRequest) (*types.QueryRedemptionRecordResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(c) + + redemptionRecord, found := k.GetRedemptionRecord(ctx, req.UnbondingRecordId, req.Address) + if !found { + return &types.QueryRedemptionRecordResponse{}, types.ErrRedemptionRecordNotFound.Wrapf( + "no redemption record found for unbonding ID %d and address %s", req.UnbondingRecordId, req.Address) + } + + // Get the unbonding time from the unbonding record + unbondingRecord, found := k.GetUnbondingRecord(ctx, req.UnbondingRecordId) + if !found { + return &types.QueryRedemptionRecordResponse{}, types.ErrUnbondingRecordNotFound + } + + redemptionRecordResponse := types.NewRedemptionRecordResponse(redemptionRecord, unbondingRecord.UnbondingCompletionTimeSeconds) + return &types.QueryRedemptionRecordResponse{RedemptionRecordResponse: &redemptionRecordResponse}, nil +} + +// Queries all redemption records with an optional filter by address +func (k Keeper) RedemptionRecords(c context.Context, req *types.QueryRedemptionRecordsRequest) (*types.QueryRedemptionRecordsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + + ctx := sdk.UnwrapSDKContext(c) + redemptionRecordResponses := []types.RedemptionRecordResponse{} + + // Create a map of estimated unbonding time by UnbondingRecord + unbondingTimeMap := map[uint64]uint64{} + unbondingRecords := k.GetAllActiveUnbondingRecords(ctx) + zone, err := k.GetHostZone(ctx) + if err != nil { + return &types.QueryRedemptionRecordsResponse{}, types.ErrHostZoneNotFound + } + fourDays := time.Duration(4) * time.Hour * 24 + unbondingLength := time.Duration(zone.UnbondingPeriodSeconds) * time.Second // 21 days + estimatedUnbondingTime := uint64(ctx.BlockTime().Add(unbondingLength).Add(fourDays).Unix()) // 21 days from now + 4 day buffer + for _, unbondingRecord := range unbondingRecords { + // Edge case: a user has submitted a redemption, but the corresponding unbonding record has not been confirmed, meaning + // the unbonding completion time is 0. Give a rough estimate. + if unbondingRecord.UnbondingCompletionTimeSeconds == 0 { + unbondingTimeMap[unbondingRecord.Id] = estimatedUnbondingTime + continue + } + unbondingTimeMap[unbondingRecord.Id] = unbondingRecord.UnbondingCompletionTimeSeconds + } + + // If they specify an address, search for that address and only return the matches + if req.Address != "" { + redemptionRecords := k.GetRedemptionRecordsFromAddress(ctx, req.Address) + // Iterate records and create response objects + redemptionRecordResponses := []types.RedemptionRecordResponse{} + for _, redemptionRecord := range redemptionRecords { + unbondingTime := unbondingTimeMap[redemptionRecord.UnbondingRecordId] + redemptionRecordResponses = append(redemptionRecordResponses, types.NewRedemptionRecordResponse(redemptionRecord, unbondingTime)) + } + return &types.QueryRedemptionRecordsResponse{ + RedemptionRecordResponses: redemptionRecordResponses, + Pagination: nil, + }, nil + } + + // If they specify an unbonding record ID, grab just the records for that ID + if req.UnbondingRecordId != 0 { + unbondingTime := unbondingTimeMap[req.UnbondingRecordId] + redemptionRecords := k.GetRedemptionRecordsFromUnbondingId(ctx, req.UnbondingRecordId) + redemptionRecordResponses := []types.RedemptionRecordResponse{} + // Iterate records and create response objects + for _, redemptionRecord := range redemptionRecords { + redemptionRecordResponses = append(redemptionRecordResponses, types.NewRedemptionRecordResponse(redemptionRecord, unbondingTime)) + } + return &types.QueryRedemptionRecordsResponse{ + RedemptionRecordResponses: redemptionRecordResponses, + Pagination: nil, + }, nil + } + + // Otherwise, return a paginated list of all redemption records + store := ctx.KVStore(k.storeKey) + redemptionRecordStore := prefix.NewStore(store, types.RedemptionRecordsKeyPrefix) + + pageRes, err := query.Paginate(redemptionRecordStore, req.Pagination, func(key []byte, value []byte) error { + var redemptionRecord types.RedemptionRecord + if err := k.cdc.Unmarshal(value, &redemptionRecord); err != nil { + return err + } + + unbondingTime := unbondingTimeMap[redemptionRecord.UnbondingRecordId] + redemptionRecordResponse := types.NewRedemptionRecordResponse(redemptionRecord, unbondingTime) + + redemptionRecordResponses = append(redemptionRecordResponses, redemptionRecordResponse) + return nil + }) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return &types.QueryRedemptionRecordsResponse{ + RedemptionRecordResponses: redemptionRecordResponses, + Pagination: pageRes, + }, nil +} + +// Queries all slash records +func (k Keeper) SlashRecords(c context.Context, req *types.QuerySlashRecordsRequest) (*types.QuerySlashRecordsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + + ctx := sdk.UnwrapSDKContext(c) + slashRecords := k.GetAllSlashRecords(ctx) + + return &types.QuerySlashRecordsResponse{SlashRecords: slashRecords}, nil +} diff --git a/x/stakedym/keeper/grpc_query_test.go b/x/stakedym/keeper/grpc_query_test.go new file mode 100644 index 0000000000..24cbc9b55a --- /dev/null +++ b/x/stakedym/keeper/grpc_query_test.go @@ -0,0 +1,257 @@ +package keeper_test + +import ( + "fmt" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +func (s *KeeperTestSuite) TestQueryHostZone() { + chainId := "chain-0" + hostZone := types.HostZone{ + ChainId: chainId, + } + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + req := &types.QueryHostZoneRequest{} + resp, err := s.App.StakedymKeeper.HostZone(sdk.WrapSDKContext(s.Ctx), req) + s.Require().NoError(err, "no error expected when querying host zone") + s.Require().Equal(chainId, resp.HostZone.ChainId, "host zone chain-id from query") +} + +func (s *KeeperTestSuite) TestQueryDelegationRecords() { + // Create active delegation records + initialDelegationRecords := s.addDelegationRecords() + + // Create an archived version of each of the above records by archiving + // the record and then recreating it in the new store + archivedDelegationRecords := []types.DelegationRecord{} + activeDelegationRecords := []types.DelegationRecord{} + for _, delegationRecord := range initialDelegationRecords { + // Update the status and archive teh record + // (which removes from the active store, and writes to the archive store) + archivedRecord := delegationRecord + archivedRecord.Status = types.DELEGATION_COMPLETE + s.App.StakedymKeeper.ArchiveDelegationRecord(s.Ctx, archivedRecord) + archivedDelegationRecords = append(archivedDelegationRecords, archivedRecord) + + // Set the original record back to the active store + delegationRecord.Status = types.TRANSFER_IN_PROGRESS + s.App.StakedymKeeper.SetDelegationRecord(s.Ctx, delegationRecord) + activeDelegationRecords = append(activeDelegationRecords, delegationRecord) + } + allDelegationRecords := append(activeDelegationRecords, archivedDelegationRecords...) + + // Test a query with no archived records + activeReq := &types.QueryDelegationRecordsRequest{IncludeArchived: false} + activeResp, err := s.App.StakedymKeeper.DelegationRecords(sdk.WrapSDKContext(s.Ctx), activeReq) + s.Require().NoError(err, "no error expected when querying active records") + + s.Require().Equal(len(activeDelegationRecords), len(activeResp.DelegationRecords), "number of active records") + s.Require().ElementsMatch(activeDelegationRecords, activeResp.DelegationRecords, "active records") + + // Test a query with all records (including archived records) + allReq := &types.QueryDelegationRecordsRequest{IncludeArchived: true} + allResp, err := s.App.StakedymKeeper.DelegationRecords(sdk.WrapSDKContext(s.Ctx), allReq) + s.Require().NoError(err, "no error expected when querying all records") + + s.Require().Equal(len(allDelegationRecords), len(allResp.DelegationRecords), "all records") + s.Require().ElementsMatch(allDelegationRecords, allResp.DelegationRecords, "all records") +} + +func (s *KeeperTestSuite) TestQueryUnbondingRecords() { + // Create active unbondin records + initialUnbondingRecords := s.addUnbondingRecords() + + // Create an archived version of each of the above records by archiving the record + // and then recreating it in the new store + archivedUnbondingRecords := []types.UnbondingRecord{} + activeUnbondingRecords := []types.UnbondingRecord{} + for _, unbondingRecord := range initialUnbondingRecords { + // Archive (which removes from the active store, and writes to the archive store) + archivedRecord := unbondingRecord + archivedRecord.Status = types.CLAIMED + s.App.StakedymKeeper.ArchiveUnbondingRecord(s.Ctx, archivedRecord) + archivedUnbondingRecords = append(archivedUnbondingRecords, archivedRecord) + + // Set the original record back to the active store + unbondingRecord.Status = types.UNBONDING_QUEUE + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, unbondingRecord) + activeUnbondingRecords = append(activeUnbondingRecords, unbondingRecord) + } + allUnbondingRecords := append(activeUnbondingRecords, archivedUnbondingRecords...) + + // Test a query with no archived records + activeReq := &types.QueryUnbondingRecordsRequest{IncludeArchived: false} + activeResp, err := s.App.StakedymKeeper.UnbondingRecords(sdk.WrapSDKContext(s.Ctx), activeReq) + s.Require().NoError(err, "no error expected when querying active records") + + s.Require().Equal(len(activeUnbondingRecords), len(activeResp.UnbondingRecords), "number of active records") + s.Require().ElementsMatch(activeUnbondingRecords, activeResp.UnbondingRecords, "active records") + + // Test a query with no all records + allReq := &types.QueryUnbondingRecordsRequest{IncludeArchived: true} + allResp, err := s.App.StakedymKeeper.UnbondingRecords(sdk.WrapSDKContext(s.Ctx), allReq) + s.Require().NoError(err, "no error expected when querying all records") + + s.Require().Equal(len(allUnbondingRecords), len(allResp.UnbondingRecords), "all records") + s.Require().ElementsMatch(allUnbondingRecords, allResp.UnbondingRecords, "all records") +} + +func (s *KeeperTestSuite) TestQueryRedemptionRecord() { + queriedUnbondingRecordId := uint64(2) + queriedAddress := "address-B" + + unbondingRecords := []types.UnbondingRecord{ + {Id: 1, UnbondingCompletionTimeSeconds: 12345}, + {Id: 2, UnbondingCompletionTimeSeconds: 12346}, + {Id: 3, UnbondingCompletionTimeSeconds: 12347}, + {Id: 4, UnbondingCompletionTimeSeconds: 12348}, + } + for _, unbondingRecord := range unbondingRecords { + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, unbondingRecord) + } + // map unbonding record id to unbonding time + unbondingTimeMap := map[uint64]uint64{} + for _, unbondingRecord := range unbondingRecords { + unbondingTimeMap[unbondingRecord.Id] = unbondingRecord.UnbondingCompletionTimeSeconds + } + + redemptionRecords := []types.RedemptionRecord{ + {UnbondingRecordId: 1, Redeemer: "address-A"}, + {UnbondingRecordId: 2, Redeemer: "address-B"}, + {UnbondingRecordId: 3, Redeemer: "address-C"}, + } + for _, redemptionRecord := range redemptionRecords { + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, redemptionRecord) + } + + req := &types.QueryRedemptionRecordRequest{ + UnbondingRecordId: queriedUnbondingRecordId, + Address: queriedAddress, + } + resp, err := s.App.StakedymKeeper.RedemptionRecord(sdk.WrapSDKContext(s.Ctx), req) + s.Require().NoError(err, "no error expected when querying redemption record") + + s.Require().Equal(queriedUnbondingRecordId, resp.RedemptionRecordResponse.RedemptionRecord.UnbondingRecordId, "redemption record unbonding ID") + s.Require().Equal(queriedAddress, resp.RedemptionRecordResponse.RedemptionRecord.Redeemer, "redemption record address") + s.Require().Equal(unbondingTimeMap[queriedUnbondingRecordId], resp.RedemptionRecordResponse.UnbondingCompletionTimeSeconds, "redemption record unbonding time") +} + +func (s *KeeperTestSuite) TestQueryAllRedemptionRecords_Address() { + queriedAddress := "address-B" + expectedUnbondingRecordIds := []uint64{2, 4} + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + UnbondingPeriodSeconds: 10000, + }) + allRedemptionRecords := []types.RedemptionRecord{ + {UnbondingRecordId: 1, Redeemer: "address-A"}, + {UnbondingRecordId: 2, Redeemer: "address-B"}, + {UnbondingRecordId: 3, Redeemer: "address-C"}, + {UnbondingRecordId: 4, Redeemer: "address-B"}, + } + for _, redemptionRecord := range allRedemptionRecords { + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, redemptionRecord) + } + + req := &types.QueryRedemptionRecordsRequest{ + Address: queriedAddress, + } + resp, err := s.App.StakedymKeeper.RedemptionRecords(sdk.WrapSDKContext(s.Ctx), req) + s.Require().NoError(err, "no error expected when querying redemption records") + s.Require().Nil(resp.Pagination, "pagination should be nil since it all fits on one page") + + actualUnbondingRecordIds := []uint64{} + for _, resp := range resp.RedemptionRecordResponses { + actualUnbondingRecordIds = append(actualUnbondingRecordIds, resp.RedemptionRecord.UnbondingRecordId) + } + s.Require().ElementsMatch(expectedUnbondingRecordIds, actualUnbondingRecordIds) +} + +func (s *KeeperTestSuite) TestQueryAllRedemptionRecords_UnbondingRecordId() { + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + UnbondingPeriodSeconds: 10000, + }) + queriedUnbondingRecordId := uint64(2) + expectedAddresss := []string{"address-B", "address-D"} + allRedemptionRecords := []types.RedemptionRecord{ + {UnbondingRecordId: 1, Redeemer: "address-A"}, + {UnbondingRecordId: 2, Redeemer: "address-B"}, + {UnbondingRecordId: 3, Redeemer: "address-C"}, + {UnbondingRecordId: 2, Redeemer: "address-D"}, + } + for _, redemptionRecord := range allRedemptionRecords { + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, redemptionRecord) + } + + req := &types.QueryRedemptionRecordsRequest{ + UnbondingRecordId: queriedUnbondingRecordId, + } + resp, err := s.App.StakedymKeeper.RedemptionRecords(sdk.WrapSDKContext(s.Ctx), req) + s.Require().NoError(err, "no error expected when querying redemption records") + s.Require().Nil(resp.Pagination, "pagination should be nil since it all fits on one page") + + actualAddresss := []string{} + for _, response := range resp.RedemptionRecordResponses { + actualAddresss = append(actualAddresss, response.RedemptionRecord.Redeemer) + } + s.Require().ElementsMatch(expectedAddresss, actualAddresss) +} + +func (s *KeeperTestSuite) TestQueryAllRedemptionRecords_Pagination() { + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + UnbondingPeriodSeconds: 10000, + }) + + // Set more records than what will fit on one page + pageLimit := 50 + numExcessRecords := 10 + for i := 0; i < pageLimit+numExcessRecords; i++ { + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, types.RedemptionRecord{ + UnbondingRecordId: uint64(i), + Redeemer: fmt.Sprintf("address-%d", i), + }) + } + + // Query with pagination + req := &types.QueryRedemptionRecordsRequest{ + Pagination: &query.PageRequest{ + Limit: uint64(pageLimit), + }, + } + resp, err := s.App.StakedymKeeper.RedemptionRecords(sdk.WrapSDKContext(s.Ctx), req) + s.Require().NoError(err, "no error expected when querying all redemption records") + + // Confirm only the first page was returned + s.Require().Equal(pageLimit, len(resp.RedemptionRecordResponses), "only the first page should be returned") + + // Attempt one more page, and it should get the remainder + req = &types.QueryRedemptionRecordsRequest{ + Pagination: &query.PageRequest{ + Key: resp.Pagination.NextKey, + }, + } + resp, err = s.App.StakedymKeeper.RedemptionRecords(sdk.WrapSDKContext(s.Ctx), req) + s.Require().NoError(err, "no error expected when querying all redemption records on second page") + s.Require().Equal(numExcessRecords, len(resp.RedemptionRecordResponses), "only the remainder should be returned") +} + +func (s *KeeperTestSuite) TestQuerySlashRecords() { + slashRecords := []types.SlashRecord{ + {Id: 1, Time: 1, NativeAmount: sdkmath.NewInt(1)}, + {Id: 2, Time: 2, NativeAmount: sdkmath.NewInt(2)}, + {Id: 3, Time: 3, NativeAmount: sdkmath.NewInt(3)}, + } + for _, slashRecord := range slashRecords { + s.App.StakedymKeeper.SetSlashRecord(s.Ctx, slashRecord) + } + + req := &types.QuerySlashRecordsRequest{} + resp, err := s.App.StakedymKeeper.SlashRecords(sdk.WrapSDKContext(s.Ctx), req) + s.Require().NoError(err, "no error expected when querying slash records") + s.Require().Equal(slashRecords, resp.SlashRecords, "slash records") +} diff --git a/x/stakedym/keeper/hooks.go b/x/stakedym/keeper/hooks.go new file mode 100644 index 0000000000..f44d72bef5 --- /dev/null +++ b/x/stakedym/keeper/hooks.go @@ -0,0 +1,88 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + epochstypes "github.com/Stride-Labs/stride/v18/x/epochs/types" +) + +// This module has the following epochly triggers +// - Handle delegations daily +// - Handle undelegations every 4 days +// - Updates the redemption rate daily +// - Check for completed unbondings hourly +// - Process claims (if applicable) hourly +// +// Note: The hourly processes are meant for actions that should run ASAP, +// but the hourly buffer makes it less expensive +func (k Keeper) BeforeEpochStart(ctx sdk.Context, epochInfo epochstypes.EpochInfo) { + epochNumber := uint64(epochInfo.CurrentEpoch) + + // Every day, refresh the redemption rate and prepare delegations + // Every 4 days, prepare undelegations + if epochInfo.Identifier == epochstypes.DAY_EPOCH { + // Update the redemption rate + // If this fails, do not proceed to the delegation or undelegation step + // Note: This must be run first because it is used when refreshing the native token + // balance in prepare undelegation + if err := k.UpdateRedemptionRate(ctx); err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Unable update redemption rate: %s", err.Error())) + return + } + + // Post the redemption rate to the oracle (if it doesn't exceed the bounds) + if err := k.PostRedemptionRateToOracles(ctx); err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Unable to post redemption rate to oracle: %s", err.Error())) + } + + // Prepare delegations by transferring the deposited tokens to the host zone + if err := k.SafelyPrepareDelegation(ctx, epochNumber, epochInfo.Duration); err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Unable to prepare delegation for epoch %d: %s", epochNumber, err.Error())) + } + + // Every few days (depending on the unbonding frequency) prepare undelegations which + // freezes the accumulating unbonding record and refreshes the native token amount + // TODO [cleanup]: replace with unbonding frequency + if epochInfo.CurrentEpoch%4 == 0 { + if err := k.SafelyPrepareUndelegation(ctx, epochNumber); err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Unable to prepare undelegations for epoch %d: %s", epochNumber, err.Error())) + } + } + } + + // Every hour, annotate finished unbondings and distribute claims + // The hourly epoch is meant for actions that should be executed asap, but have a + // relaxed SLA. It makes it slightly less expensive than running every block + if epochInfo.Identifier == epochstypes.HOUR_EPOCH { + k.MarkFinishedUnbondings(ctx) + + if err := k.SafelyDistributeClaims(ctx); err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Unable to distribute claims for epoch %d: %s", epochNumber, err.Error())) + } + } + + // Every mint epoch, liquid stake fees and distribute to fee collector + if epochInfo.Identifier == epochstypes.MINT_EPOCH { + if err := k.SafelyLiquidStakeAndDistributeFees(ctx); err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Unable to liquid stake and distribute fees this epoch %d: %s", epochNumber, err.Error())) + } + } +} + +type Hooks struct { + k Keeper +} + +var _ epochstypes.EpochHooks = Hooks{} + +func (k Keeper) Hooks() Hooks { + return Hooks{k} +} + +func (h Hooks) BeforeEpochStart(ctx sdk.Context, epochInfo epochstypes.EpochInfo) { + h.k.BeforeEpochStart(ctx, epochInfo) +} + +func (h Hooks) AfterEpochEnd(ctx sdk.Context, epochInfo epochstypes.EpochInfo) {} diff --git a/x/stakedym/keeper/host_zone.go b/x/stakedym/keeper/host_zone.go new file mode 100644 index 0000000000..5772f7dd4a --- /dev/null +++ b/x/stakedym/keeper/host_zone.go @@ -0,0 +1,47 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// Writes a host zone to the store +func (k Keeper) SetHostZone(ctx sdk.Context, hostZone types.HostZone) { + store := ctx.KVStore(k.storeKey) + hostZoneBz := k.cdc.MustMarshal(&hostZone) + store.Set(types.HostZoneKey, hostZoneBz) +} + +// Reads a host zone from the store +// There should always be a host zone, so this should error if it is not found +func (k Keeper) GetHostZone(ctx sdk.Context) (hostZone types.HostZone, err error) { + store := ctx.KVStore(k.storeKey) + hostZoneBz := store.Get(types.HostZoneKey) + + if len(hostZoneBz) == 0 { + return hostZone, types.ErrHostZoneNotFound.Wrapf("No HostZone found, there must be exactly one HostZone!") + } + + k.cdc.MustUnmarshal(hostZoneBz, &hostZone) + return hostZone, nil +} + +// Removes a host zone from the store +// Note: This is only for testing - it should never be used elsewhere +func (k Keeper) RemoveHostZone(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.HostZoneKey) +} + +// Reads a host zone from the store and errors if the host zone is halted +func (k Keeper) GetUnhaltedHostZone(ctx sdk.Context) (hostZone types.HostZone, err error) { + hostZone, err = k.GetHostZone(ctx) + if err != nil { + return hostZone, err + } + if hostZone.Halted { + return hostZone, types.ErrHostZoneHalted.Wrapf("host zone %s is halted", hostZone.ChainId) + } + return hostZone, nil +} diff --git a/x/stakedym/keeper/host_zone_test.go b/x/stakedym/keeper/host_zone_test.go new file mode 100644 index 0000000000..f4f17b15f6 --- /dev/null +++ b/x/stakedym/keeper/host_zone_test.go @@ -0,0 +1,83 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// Helper function to create the singleton HostZone with attributes +func (s *KeeperTestSuite) initializeHostZone() types.HostZone { + hostZone := types.HostZone{ + ChainId: "DYMENSION", + NativeTokenDenom: "adym", + NativeTokenIbcDenom: "ibc/adym", + TransferChannelId: "channel-0", + DelegationAddress: "dym0384a", + RewardAddress: "dym144f42e9", + DepositAddress: "stride8abb3e", + RedemptionAddress: "stride3400de1", + ClaimAddress: "stride00b1a83", + LastRedemptionRate: sdk.MustNewDecFromStr("1.0"), + RedemptionRate: sdk.MustNewDecFromStr("1.0"), + MinRedemptionRate: sdk.MustNewDecFromStr("0.95"), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.10"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.97"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.07"), + DelegatedBalance: sdk.NewInt(1_000_000), + Halted: false, + } + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + return hostZone +} + +func (s *KeeperTestSuite) TestGetHostZone() { + savedHostZone := s.initializeHostZone() + loadedHostZone := s.MustGetHostZone() + s.Require().Equal(savedHostZone, loadedHostZone) +} + +func (s *KeeperTestSuite) TestRemoveHostZone() { + s.initializeHostZone() + s.App.StakedymKeeper.RemoveHostZone(s.Ctx) + _, err := s.App.StakedymKeeper.GetHostZone(s.Ctx) + s.Require().ErrorContains(err, "host zone not found") +} + +func (s *KeeperTestSuite) TestSetHostZone() { + hostZone := s.initializeHostZone() + + hostZone.RedemptionRate = hostZone.RedemptionRate.Add(sdk.MustNewDecFromStr("0.1")) + hostZone.DelegatedBalance = hostZone.DelegatedBalance.Add(sdk.NewInt(100_000)) + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + loadedHostZone := s.MustGetHostZone() + s.Require().Equal(hostZone, loadedHostZone) +} + +func (s *KeeperTestSuite) TestGetUnhaltedHostZone() { + initialHostZone := types.HostZone{ + ChainId: "chain-0", + } + + // Attempt to get a host zone when one has not been created yet - it should error + _, err := s.App.StakedymKeeper.GetUnhaltedHostZone(s.Ctx) + s.Require().ErrorContains(err, "host zone not found") + + // Set a non-halted zone + initialHostZone.Halted = false + s.App.StakedymKeeper.SetHostZone(s.Ctx, initialHostZone) + + // Confirm there's no error when fetching it + actualHostZone, err := s.App.StakedymKeeper.GetUnhaltedHostZone(s.Ctx) + s.Require().NoError(err, "no error expected when host zone is active") + s.Require().Equal(initialHostZone.ChainId, actualHostZone.ChainId, "chain-id") + + // Set a halted zone + initialHostZone.Halted = true + s.App.StakedymKeeper.SetHostZone(s.Ctx, initialHostZone) + + // Confirm there's a halt error + _, err = s.App.StakedymKeeper.GetUnhaltedHostZone(s.Ctx) + s.Require().ErrorContains(err, "host zone is halted") +} diff --git a/x/stakedym/keeper/ibc.go b/x/stakedym/keeper/ibc.go new file mode 100644 index 0000000000..9d4fb1fc67 --- /dev/null +++ b/x/stakedym/keeper/ibc.go @@ -0,0 +1,81 @@ +package keeper + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + + icacallbacktypes "github.com/Stride-Labs/stride/v18/x/icacallbacks/types" + "github.com/Stride-Labs/stride/v18/x/stakedym/types" + + "github.com/Stride-Labs/stride/v18/x/icacallbacks" +) + +func (k Keeper) ArchiveFailedTransferRecord(ctx sdk.Context, recordId uint64) error { + // Mark the record as a failed transfer + delegationRecord, found := k.GetDelegationRecord(ctx, recordId) + if !found { + return types.ErrDelegationRecordNotFound.Wrapf("delegation record not found for %d", recordId) + } + delegationRecord.Status = types.TRANSFER_FAILED + k.ArchiveDelegationRecord(ctx, delegationRecord) + + return nil +} + +// OnTimeoutPacket: Delete the DelegationRecord +func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet) error { + recordId, recordIdFound := k.GetTransferInProgressRecordId(ctx, packet.SourceChannel, packet.Sequence) + if !recordIdFound { + return nil + } + + err := k.ArchiveFailedTransferRecord(ctx, recordId) + if err != nil { + return err + } + + // Clean up the callback store + k.RemoveTransferInProgressRecordId(ctx, packet.SourceChannel, packet.Sequence) + + return nil +} + +// OnAcknowledgementPacket success: Update the DelegationRecord's status to DELEGATION_QUEUE +// OnAcknowledgementPacket failure: Delete the DelegationRecord +func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte) error { + recordId, recordIdFound := k.GetTransferInProgressRecordId(ctx, packet.SourceChannel, packet.Sequence) + if !recordIdFound { + return nil + } + + // Parse whether the ack was successful or not + isICATx := false + ackResponse, err := icacallbacks.UnpackAcknowledgementResponse(ctx, k.Logger(ctx), acknowledgement, isICATx) + if err != nil { + return err + } + + // Grab the delegation record + record, found := k.GetDelegationRecord(ctx, recordId) + if !found { + return errorsmod.Wrapf(err, "record not found for record id %d", recordId) + } + + // If the ack was successful, update the record id to DELEGATION_QUEUE + if ackResponse.Status == icacallbacktypes.AckResponseStatus_SUCCESS { + record.Status = types.DELEGATION_QUEUE + k.SetDelegationRecord(ctx, record) + } else { + // Otherwise there must be an error, so archive the record + err := k.ArchiveFailedTransferRecord(ctx, recordId) + if err != nil { + return err + } + } + + // Clean up the callback store + k.RemoveTransferInProgressRecordId(ctx, packet.SourceChannel, packet.Sequence) + + return nil +} diff --git a/x/stakedym/keeper/ibc_test.go b/x/stakedym/keeper/ibc_test.go new file mode 100644 index 0000000000..1429805356 --- /dev/null +++ b/x/stakedym/keeper/ibc_test.go @@ -0,0 +1,243 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +type PacketCallbackTestCase struct { + ChannelId string + OriginalSequence uint64 + RetrySequence uint64 + Token sdk.Coin + Packet channeltypes.Packet + Record types.DelegationRecord +} + +func (s *KeeperTestSuite) SetupTestHandleRecordUpdatePacket() PacketCallbackTestCase { + senderAccount := s.TestAccs[0] + + // IBC transfer packet data + sequence := uint64(1) + channelId := "channel-0" + + // Pending delegation record associated with transfer + record := types.DelegationRecord{ + Id: 1, + NativeAmount: sdk.NewInt(0), + Status: types.TRANSFER_IN_PROGRESS, + } + + // Write record to store + s.App.StakedymKeeper.SetDelegationRecord(s.Ctx, record) + + // Add the pending record to the store + s.App.StakedymKeeper.SetTransferInProgressRecordId(s.Ctx, channelId, sequence, record.Id) + + // Build the IBC packet + transferMetadata := transfertypes.FungibleTokenPacketData{ + Denom: "denom", + Sender: senderAccount.String(), + } + packet := channeltypes.Packet{ + Sequence: sequence, + SourceChannel: channelId, + Data: transfertypes.ModuleCdc.MustMarshalJSON(&transferMetadata), + } + + return PacketCallbackTestCase{ + ChannelId: channelId, + OriginalSequence: sequence, + Packet: packet, + Record: record, + } +} + +func (s *KeeperTestSuite) TestArchiveFailedTransferRecord() { + // Create an initial record + recordId := uint64(1) + s.App.StakedymKeeper.SetDelegationRecord(s.Ctx, types.DelegationRecord{ + Id: recordId, + }) + + // Update the hash to failed + err := s.App.StakedymKeeper.ArchiveFailedTransferRecord(s.Ctx, recordId) + s.Require().NoError(err, "no error expected when archiving transfer record") + + // Confirm it was updated + delegationRecord, found := s.App.StakedymKeeper.GetArchivedDelegationRecord(s.Ctx, recordId) + s.Require().True(found, "delegation record should have been archived") + s.Require().Equal(types.TRANSFER_FAILED, delegationRecord.Status, "delegation record status") + + // Check that an invalid ID errors + invalidRecordId := uint64(99) + err = s.App.StakedymKeeper.ArchiveFailedTransferRecord(s.Ctx, invalidRecordId) + s.Require().ErrorContains(err, "delegation record not found") +} + +// -------------------------------------------------------------- +// OnTimeoutPacket +// -------------------------------------------------------------- + +func (s *KeeperTestSuite) TestOnTimeoutPacket_Successful() { + tc := s.SetupTestHandleRecordUpdatePacket() + + // Call OnTimeoutPacket + err := s.App.StakedymKeeper.OnTimeoutPacket(s.Ctx, tc.Packet) + s.Require().NoError(err, "no error expected when calling OnTimeoutPacket") + + s.verifyDelegationRecordArchived(tc) +} + +func (s *KeeperTestSuite) TestOnTimeoutPacket_NoOp() { + tc := s.SetupTestHandleRecordUpdatePacket() + + // Get all delegation records + recordsBefore := s.getAllRecords(tc) + + // Remove the callback data + s.App.StakedymKeeper.RemoveTransferInProgressRecordId(s.Ctx, tc.ChannelId, tc.OriginalSequence) + + // Should be a no-op since there's no callback data + err := s.App.StakedymKeeper.OnTimeoutPacket(s.Ctx, tc.Packet) + s.Require().NoError(err, "no error expected when calling OnTimeoutPacket") + + s.verifyNoRecordsChanged(tc, recordsBefore) +} + +// -------------------------------------------------------------- +// OnAcknowledgementPacket +// -------------------------------------------------------------- + +func (s *KeeperTestSuite) TestOnAcknowledgementPacket_AckSuccess() { + tc := s.SetupTestHandleRecordUpdatePacket() + + // Build a successful ack + ackSuccess := transfertypes.ModuleCdc.MustMarshalJSON(&channeltypes.Acknowledgement{ + Response: &channeltypes.Acknowledgement_Result{ + Result: []byte{1}, // just has to be non-empty + }, + }) + + // Call OnAckPacket with the successful ack + err := s.App.StakedymKeeper.OnAcknowledgementPacket(s.Ctx, tc.Packet, ackSuccess) + s.Require().NoError(err, "no error expected during OnAckPacket") + + s.verifyDelegationRecordQueued(tc) +} + +func (s *KeeperTestSuite) TestOnAcknowledgementPacket_AckFailure() { + tc := s.SetupTestHandleRecordUpdatePacket() + + // Build an error ack + ackFailure := transfertypes.ModuleCdc.MustMarshalJSON(&channeltypes.Acknowledgement{ + Response: &channeltypes.Acknowledgement_Error{}, + }) + + // Call OnAckPacket with the successful ack + err := s.App.StakedymKeeper.OnAcknowledgementPacket(s.Ctx, tc.Packet, ackFailure) + s.Require().NoError(err, "no error expected during OnAckPacket") + + s.verifyDelegationRecordArchived(tc) +} + +func (s *KeeperTestSuite) TestOnAcknowledgementPacket_InvalidAck() { + tc := s.SetupTestHandleRecordUpdatePacket() + + // Get all delegation records + recordsBefore := s.getAllRecords(tc) + + // Build an invalid ack to force an error + invalidAck := transfertypes.ModuleCdc.MustMarshalJSON(&channeltypes.Acknowledgement{ + Response: &channeltypes.Acknowledgement_Result{ + Result: []byte{}, // empty result causes an error + }, + }) + + // Call OnAckPacket with the invalid ack + err := s.App.StakedymKeeper.OnAcknowledgementPacket(s.Ctx, tc.Packet, invalidAck) + s.Require().ErrorContains(err, "invalid acknowledgement") + + // Verify store is unchanged + s.verifyNoRecordsChanged(tc, recordsBefore) +} + +// record not found for record id case +func (s *KeeperTestSuite) TestOnAcknowledgementPacket_NoOp() { + tc := s.SetupTestHandleRecordUpdatePacket() + + // Get all delegation records + recordsBefore := s.getAllRecords(tc) + + // Remove the record id so that there is no action necessary in the callback + s.App.StakedymKeeper.RemoveTransferInProgressRecordId(s.Ctx, tc.ChannelId, tc.OriginalSequence) + + // Call OnAckPacket and confirm there was no error + // The ack argument here doesn't matter cause the no-op check is upstream + err := s.App.StakedymKeeper.OnAcknowledgementPacket(s.Ctx, tc.Packet, []byte{}) + s.Require().NoError(err, "no error expected during on ack packet") + + // Verify store is unchanged + s.verifyNoRecordsChanged(tc, recordsBefore) +} + +// -------------------------------------------------------------- +// Helpers +// -------------------------------------------------------------- + +// Helper function to verify the record was updated after a successful transfer +func (s *KeeperTestSuite) verifyDelegationRecordQueued(tc PacketCallbackTestCase) { + // Confirm the DelegationRecord is still in the active store + record, found := s.App.StakedymKeeper.GetDelegationRecord(s.Ctx, tc.Record.Id) + s.Require().True(found, "record should have been found") + // Confirm the record was not archived + _, found = s.App.StakedymKeeper.GetArchivedDelegationRecord(s.Ctx, tc.Record.Id) + s.Require().False(found, "record should not be archived") + + // Confirm the record is unchanged, except for the status + tc.Record.Status = types.DELEGATION_QUEUE + s.Require().Equal(tc.Record, record, "record should have been archived") + + // Confirm the transfer in progress was removed + _, found = s.App.StakedymKeeper.GetTransferInProgressRecordId(s.Ctx, tc.ChannelId, tc.OriginalSequence) + s.Require().False(found, "transfer in progress should have been removed") +} + +// Helper function to verify record was archived after a failed or timed out transfer +func (s *KeeperTestSuite) verifyDelegationRecordArchived(tc PacketCallbackTestCase) { + // Confirm the DelegationRecord was archived + archivedRecord, found := s.App.StakedymKeeper.GetArchivedDelegationRecord(s.Ctx, tc.Record.Id) + s.Require().True(found, "record should have been found in the archive store") + // Confirm the record is no longer in the active store + _, found = s.App.StakedymKeeper.GetDelegationRecord(s.Ctx, tc.Record.Id) + s.Require().False(found, "record should have been removed from the store") + + // Confirm the record is unchanged, except for the Status + tc.Record.Status = types.TRANSFER_FAILED + s.Require().Equal(tc.Record, archivedRecord, "record should have been archived") + + // Confirm the transfer in progress was removed + _, found = s.App.StakedymKeeper.GetTransferInProgressRecordId(s.Ctx, tc.ChannelId, tc.OriginalSequence) + s.Require().False(found, "transfer in progress should have been removed") +} + +// Helper function to grab both active and archived delegation records +func (s *KeeperTestSuite) getAllRecords(tc PacketCallbackTestCase) (allRecords []types.DelegationRecord) { + // Get all delegation records + activeRecords := s.App.StakedymKeeper.GetAllActiveDelegationRecords(s.Ctx) + archiveRecords := s.App.StakedymKeeper.GetAllArchivedDelegationRecords(s.Ctx) + // append the records + allRecords = append(activeRecords, archiveRecords...) + return allRecords +} + +// Helper function to verify no records were updated +func (s *KeeperTestSuite) verifyNoRecordsChanged(tc PacketCallbackTestCase, recordsBefore []types.DelegationRecord) { + // Get current records + recordsAfter := s.getAllRecords(tc) + // Compare to records before + s.Require().Equal(recordsBefore, recordsAfter, "records should be unchanged") +} diff --git a/x/stakedym/keeper/invariants.go b/x/stakedym/keeper/invariants.go new file mode 100644 index 0000000000..769a29b948 --- /dev/null +++ b/x/stakedym/keeper/invariants.go @@ -0,0 +1,30 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/utils" +) + +func (k Keeper) HaltZone(ctx sdk.Context) { + // Set the halted flag on the zone + hostZone, err := k.GetHostZone(ctx) + if err != nil { + // No panic - we don't want to halt the chain! Just the zone. + // log the error + k.Logger(ctx).Error(fmt.Sprintf("Unable to get host zone: %s", err.Error())) + return + } + hostZone.Halted = true + k.SetHostZone(ctx, hostZone) + + // set rate limit on stAsset + stDenom := utils.StAssetDenomFromHostZoneDenom(hostZone.NativeTokenDenom) + k.ratelimitKeeper.AddDenomToBlacklist(ctx, stDenom) + + k.Logger(ctx).Error(fmt.Sprintf("[INVARIANT BROKEN!!!] %s's RR is %s.", hostZone.GetChainId(), hostZone.RedemptionRate.String())) + + EmitHaltZoneEvent(ctx, hostZone) +} diff --git a/x/stakedym/keeper/invariants_test.go b/x/stakedym/keeper/invariants_test.go new file mode 100644 index 0000000000..d269227a3b --- /dev/null +++ b/x/stakedym/keeper/invariants_test.go @@ -0,0 +1,24 @@ +package keeper_test + +import ( + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +func (s *KeeperTestSuite) TestHaltZone() { + // Set a non-halted host zone + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + NativeTokenDenom: HostNativeDenom, + Halted: false, + }) + + // Halt the zone + s.App.StakedymKeeper.HaltZone(s.Ctx) + + // Confirm it's halted + hostZone := s.MustGetHostZone() + s.Require().True(hostZone.Halted, "host zone should be halted") + + // Confirm denom is blacklisted + isBlacklisted := s.App.RatelimitKeeper.IsDenomBlacklisted(s.Ctx, StDenom) + s.Require().True(isBlacklisted, "halt zone should blacklist the stAsset denom") +} diff --git a/x/stakedym/keeper/keeper.go b/x/stakedym/keeper/keeper.go new file mode 100644 index 0000000000..4e63d93bd1 --- /dev/null +++ b/x/stakedym/keeper/keeper.go @@ -0,0 +1,46 @@ +package keeper + +import ( + "fmt" + + "github.com/cometbft/cometbft/libs/log" + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +type Keeper struct { + cdc codec.BinaryCodec + storeKey storetypes.StoreKey + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper + icaOracleKeeper types.ICAOracleKeeper + ratelimitKeeper types.RatelimitKeeper + transferKeeper types.TransferKeeper +} + +func NewKeeper( + cdc codec.BinaryCodec, + storeKey storetypes.StoreKey, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, + icaOracleKeeper types.ICAOracleKeeper, + ratelimitKeeper types.RatelimitKeeper, + transferKeeper types.TransferKeeper, +) *Keeper { + return &Keeper{ + cdc: cdc, + storeKey: storeKey, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + icaOracleKeeper: icaOracleKeeper, + ratelimitKeeper: ratelimitKeeper, + transferKeeper: transferKeeper, + } +} + +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} diff --git a/x/stakedym/keeper/keeper_test.go b/x/stakedym/keeper/keeper_test.go new file mode 100644 index 0000000000..4b3fb3d676 --- /dev/null +++ b/x/stakedym/keeper/keeper_test.go @@ -0,0 +1,50 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/Stride-Labs/stride/v18/app/apptesting" + "github.com/Stride-Labs/stride/v18/x/stakedym/keeper" + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +const ( + HostChainId = "chain-0" + HostNativeDenom = "denom" + HostIBCDenom = "ibc/denom" + StDenom = "stdenom" + + ValidOperator = "stride1njt6kn0c2a2w5ax8mlm9k0fmcc8tyjgh7s8hu8" + ValidTxHashDefault = "BBD978ADDBF580AC2981E351A3EA34AA9D7B57631E9CE21C27C2C63A5B13BDA9" + ValidTxHashNew = "FEFC69DCDF00E2BF971A61D34944871F607C84787CA9A69715B360A767FE6862" +) + +type KeeperTestSuite struct { + apptesting.AppTestHelper +} + +func (s *KeeperTestSuite) SetupTest() { + s.Setup() +} + +// Dynamically gets the MsgServer for this module's keeper +// this function must be used so that the MsgServer is always created with the most updated App context +// +// which can change depending on the type of test +// (e.g. tests with only one Stride chain vs tests with multiple chains and IBC support) +func (s *KeeperTestSuite) GetMsgServer() types.MsgServer { + return keeper.NewMsgServerImpl(s.App.StakedymKeeper) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +// Helper function to get a host zone and confirm there's no error +func (s *KeeperTestSuite) MustGetHostZone() types.HostZone { + hostZone, err := s.App.StakedymKeeper.GetHostZone(s.Ctx) + s.Require().NoError(err, "no error expected when getting host zone") + return hostZone +} diff --git a/x/stakedym/keeper/msg_server.go b/x/stakedym/keeper/msg_server.go new file mode 100644 index 0000000000..b5114945aa --- /dev/null +++ b/x/stakedym/keeper/msg_server.go @@ -0,0 +1,285 @@ +package keeper + +import ( + "context" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/utils" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl returns an implementation of the MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} + +// User transaction to liquid stake native tokens into stTokens +func (k msgServer) LiquidStake(goCtx context.Context, msg *types.MsgLiquidStake) (*types.MsgLiquidStakeResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + stToken, err := k.Keeper.LiquidStake(ctx, msg.Staker, msg.NativeAmount) + if err != nil { + return nil, err + } + return &types.MsgLiquidStakeResponse{StToken: stToken}, nil +} + +// User transaction to redeem stake stTokens into native tokens +func (k msgServer) RedeemStake(goCtx context.Context, msg *types.MsgRedeemStake) (*types.MsgRedeemStakeResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + nativeToken, err := k.Keeper.RedeemStake(ctx, msg.Redeemer, msg.StTokenAmount) + if err != nil { + return nil, err + } + return &types.MsgRedeemStakeResponse{NativeToken: nativeToken}, nil +} + +// Operator transaction to confirm a delegation was submitted on the host chain +func (k msgServer) ConfirmDelegation(goCtx context.Context, msg *types.MsgConfirmDelegation) (*types.MsgConfirmDelegationResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // gate this transaction to either admin (SAFE or OPERATOR) address + if err := k.CheckIsSafeOrOperatorAddress(ctx, msg.Operator); err != nil { + return nil, err + } + + err := k.Keeper.ConfirmDelegation(ctx, msg.RecordId, msg.TxHash, msg.Operator) + if err != nil { + return nil, err + } + + return &types.MsgConfirmDelegationResponse{}, nil +} + +// Operator transaction to confirm an undelegation was submitted on the host chain +func (k msgServer) ConfirmUndelegation(goCtx context.Context, msg *types.MsgConfirmUndelegation) (*types.MsgConfirmUndelegationResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // gate this transaction to either admin (SAFE or OPERATOR) address + if err := k.CheckIsSafeOrOperatorAddress(ctx, msg.Operator); err != nil { + return nil, err + } + + err := k.Keeper.ConfirmUndelegation(ctx, msg.RecordId, msg.TxHash, msg.Operator) + if err != nil { + return nil, err + } + + return &types.MsgConfirmUndelegationResponse{}, err +} + +// Operator transaction to confirm unbonded tokens were transferred back to stride +func (k msgServer) ConfirmUnbondedTokenSweep(goCtx context.Context, msg *types.MsgConfirmUnbondedTokenSweep) (*types.MsgConfirmUnbondedTokenSweepResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // gate this transaction to either admin (SAFE or OPERATOR) address + if err := k.CheckIsSafeOrOperatorAddress(ctx, msg.Operator); err != nil { + return nil, err + } + + err := k.Keeper.ConfirmUnbondedTokenSweep(ctx, msg.RecordId, msg.TxHash, msg.Operator) + if err != nil { + return nil, err + } + + return &types.MsgConfirmUnbondedTokenSweepResponse{}, nil +} + +// SAFE transaction to adjust the delegated balance after a validator was slashed +// - creates a slash record as a log +// - allow negative amounts in case we want to fix our record keeping +func (k msgServer) AdjustDelegatedBalance(goCtx context.Context, msg *types.MsgAdjustDelegatedBalance) (*types.MsgAdjustDelegatedBalanceResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // gate this transaction to only the SAFE address + if err := k.CheckIsSafeAddress(ctx, msg.Operator); err != nil { + return nil, err + } + + // add offset to the delegated balance and write to host zone + // Note: we're intentionally not checking the zone is halted + hostZone, err := k.GetHostZone(ctx) + if err != nil { + return nil, err + } + hostZone.DelegatedBalance = hostZone.DelegatedBalance.Add(msg.DelegationOffset) + + // safety check that this will not cause the delegated balance to be negative + if hostZone.DelegatedBalance.IsNegative() { + return nil, types.ErrNegativeNotAllowed.Wrapf("offset would cause the delegated balance to be negative") + } + k.SetHostZone(ctx, hostZone) + + // create a corresponding slash record + latestSlashRecordId := k.IncrementSlashRecordId(ctx) + slashRecord := types.SlashRecord{ + Id: latestSlashRecordId, + Time: uint64(ctx.BlockTime().Unix()), + NativeAmount: msg.DelegationOffset, + ValidatorAddress: msg.ValidatorAddress, + } + k.SetSlashRecord(ctx, slashRecord) + + return &types.MsgAdjustDelegatedBalanceResponse{}, nil +} + +// Adjusts the inner redemption rate bounds on the host zone +func (k msgServer) UpdateInnerRedemptionRateBounds(goCtx context.Context, msg *types.MsgUpdateInnerRedemptionRateBounds) (*types.MsgUpdateInnerRedemptionRateBoundsResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // gate this transaction to the BOUNDS address + if err := utils.ValidateAdminAddress(msg.Creator); err != nil { + return nil, types.ErrInvalidAdmin + } + + // Fetch the zone + zone, err := k.GetHostZone(ctx) + if err != nil { + return nil, err + } + + // Get the outer bounds + maxOuterBound := zone.MaxRedemptionRate + minOuterBound := zone.MinRedemptionRate + + // Confirm the inner bounds are within the outer bounds + maxInnerBound := msg.MaxInnerRedemptionRate + minInnerBound := msg.MinInnerRedemptionRate + if maxInnerBound.GT(maxOuterBound) { + return nil, types.ErrInvalidRedemptionRateBounds + } + if minInnerBound.LT(minOuterBound) { + return nil, types.ErrInvalidRedemptionRateBounds + } + + // Set the inner bounds on the host zone + zone.MinInnerRedemptionRate = minInnerBound + zone.MaxInnerRedemptionRate = maxInnerBound + + // Update the host zone + k.SetHostZone(ctx, zone) + + return &types.MsgUpdateInnerRedemptionRateBoundsResponse{}, nil +} + +// Unhalts the host zone if redemption rates were exceeded +// BOUNDS: verified in ValidateBasic +func (k msgServer) ResumeHostZone(goCtx context.Context, msg *types.MsgResumeHostZone) (*types.MsgResumeHostZoneResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // gate this transaction to the BOUNDS address + if err := utils.ValidateAdminAddress(msg.Creator); err != nil { + return nil, types.ErrInvalidAdmin + } + + // Note: of course we don't want to fail this if the zone is halted! + zone, err := k.GetHostZone(ctx) + if err != nil { + return nil, err + } + + // Check the zone is halted + if !zone.Halted { + return nil, errorsmod.Wrapf(types.ErrHostZoneNotHalted, "zone is not halted") + } + + stDenom := utils.StAssetDenomFromHostZoneDenom(zone.NativeTokenDenom) + k.ratelimitKeeper.RemoveDenomFromBlacklist(ctx, stDenom) + + // Resume zone + zone.Halted = false + k.SetHostZone(ctx, zone) + + return &types.MsgResumeHostZoneResponse{}, nil +} + +// trigger updating the redemption rate +func (k msgServer) RefreshRedemptionRate(goCtx context.Context, msgTriggerRedemptionRate *types.MsgRefreshRedemptionRate) (*types.MsgRefreshRedemptionRateResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // gate this transaction to only the SAFE address + if err := k.CheckIsSafeAddress(ctx, msgTriggerRedemptionRate.Creator); err != nil { + return nil, err + } + + err := k.UpdateRedemptionRate(ctx) + + return &types.MsgRefreshRedemptionRateResponse{}, err +} + +// overwrite a delegation record +func (k msgServer) OverwriteDelegationRecord(goCtx context.Context, msgOverwriteDelegationRecord *types.MsgOverwriteDelegationRecord) (*types.MsgOverwriteDelegationRecordResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // gate this transaction to only the SAFE address + if err := k.CheckIsSafeAddress(ctx, msgOverwriteDelegationRecord.Creator); err != nil { + return nil, err + } + + k.Keeper.SetDelegationRecord(ctx, *msgOverwriteDelegationRecord.DelegationRecord) + + return &types.MsgOverwriteDelegationRecordResponse{}, nil +} + +// overwrite a unbonding record +func (k msgServer) OverwriteUnbondingRecord(goCtx context.Context, msgOverwriteUnbondingRecord *types.MsgOverwriteUnbondingRecord) (*types.MsgOverwriteUnbondingRecordResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // gate this transaction to only the SAFE address + if err := k.CheckIsSafeAddress(ctx, msgOverwriteUnbondingRecord.Creator); err != nil { + return nil, err + } + + k.Keeper.SetUnbondingRecord(ctx, *msgOverwriteUnbondingRecord.UnbondingRecord) + + return &types.MsgOverwriteUnbondingRecordResponse{}, nil +} + +// overwrite a redemption record +func (k msgServer) OverwriteRedemptionRecord(goCtx context.Context, msgOverwriteRedemptionRecord *types.MsgOverwriteRedemptionRecord) (*types.MsgOverwriteRedemptionRecordResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // gate this transaction to only the SAFE address + if err := k.CheckIsSafeAddress(ctx, msgOverwriteRedemptionRecord.Creator); err != nil { + return nil, err + } + + k.Keeper.SetRedemptionRecord(ctx, *msgOverwriteRedemptionRecord.RedemptionRecord) + + return &types.MsgOverwriteRedemptionRecordResponse{}, nil +} + +// Sets the OPERATOR address for the host zone +// - only SAFE can execute this message +func (k msgServer) SetOperatorAddress(goCtx context.Context, msg *types.MsgSetOperatorAddress) (*types.MsgSetOperatorAddressResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // gate this transaction to only the SAFE address + if err := k.CheckIsSafeAddress(ctx, msg.Signer); err != nil { + return nil, err + } + + // Fetch the zone + // Note: we're intentionally not checking the zone is halted + zone, err := k.GetHostZone(ctx) + if err != nil { + return nil, err + } + + // set the operator field + zone.OperatorAddressOnStride = msg.Operator + + // Update the host zone + k.SetHostZone(ctx, zone) + + return &types.MsgSetOperatorAddressResponse{}, nil +} diff --git a/x/stakedym/keeper/msg_server_test.go b/x/stakedym/keeper/msg_server_test.go new file mode 100644 index 0000000000..f378b2aa67 --- /dev/null +++ b/x/stakedym/keeper/msg_server_test.go @@ -0,0 +1,634 @@ +package keeper_test + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/app/apptesting" + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// ---------------------------------------------- +// MsgLiquidStake +// ---------------------------------------------- + +// More granular testing of liquid stake is done in the keeper function +// This just tests the msg server wrapper +func (s *KeeperTestSuite) TestMsgServerLiquidStake() { + tc := s.DefaultSetupTestLiquidStake() + + // Attempt a successful liquid stake + validMsg := types.MsgLiquidStake{ + Staker: tc.stakerAddress.String(), + NativeAmount: tc.liquidStakeAmount, + } + resp, err := s.GetMsgServer().LiquidStake(sdk.UnwrapSDKContext(s.Ctx), &validMsg) + s.Require().NoError(err, "no error expected during liquid stake") + s.Require().Equal(tc.expectedStAmount.Int64(), resp.StToken.Amount.Int64(), "stToken amount") + + s.ConfirmLiquidStakeTokenTransfer(tc) + + // Attempt a liquid stake again, it should fail now that the staker is out of funds + _, err = s.GetMsgServer().LiquidStake(sdk.UnwrapSDKContext(s.Ctx), &validMsg) + s.Require().ErrorContains(err, "insufficient funds") +} + +// ---------------------------------------------- +// MsgConfirmDelegation +// ---------------------------------------------- + +func (s *KeeperTestSuite) SetupDelegationRecordsAndHostZone() { + s.SetupDelegationRecords() + + safeAddress := s.TestAccs[0].String() + operatorAddress := s.TestAccs[1].String() + hostZone := s.initializeHostZone() + hostZone.OperatorAddressOnStride = operatorAddress + hostZone.SafeAddressOnStride = safeAddress + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) +} + +// Verify that ConfirmDelegation succeeds, and non-admins cannot call it +func (s *KeeperTestSuite) TestConfirmDelegation() { + safeAddress := s.TestAccs[0].String() + operatorAddress := s.TestAccs[1].String() + nonAdminAddress := s.TestAccs[2].String() + + // Confirm that ConfirmDelegation can be called by the operator address + s.SetupDelegationRecordsAndHostZone() + msgConfirmDelegationOperator := types.MsgConfirmDelegation{ + Operator: operatorAddress, + RecordId: 6, + TxHash: ValidTxHashNew, + } + _, err := s.GetMsgServer().ConfirmDelegation(s.Ctx, &msgConfirmDelegationOperator) + s.Require().NoError(err, "operator should be able to confirm delegation") + + // Confirm that ConfirmDelegation can be called by the safe address + s.SetupDelegationRecordsAndHostZone() + msgConfirmDelegationSafe := types.MsgConfirmDelegation{ + Operator: safeAddress, + RecordId: 6, + TxHash: ValidTxHashNew, + } + _, err = s.GetMsgServer().ConfirmDelegation(s.Ctx, &msgConfirmDelegationSafe) + s.Require().NoError(err, "safe should be able to confirm delegation") + + // Confirm that ConfirmDelegation cannot be called by a non-admin address + s.SetupDelegationRecordsAndHostZone() + msgConfirmDelegationNonAdmin := types.MsgConfirmDelegation{ + Operator: nonAdminAddress, + RecordId: 6, + TxHash: ValidTxHashNew, + } + _, err = s.GetMsgServer().ConfirmDelegation(s.Ctx, &msgConfirmDelegationNonAdmin) + s.Require().Error(err, "non-admin should not be able to confirm delegation") +} + +// ---------------------------------------------- +// MsgConfirmUndelegation +// ---------------------------------------------- + +// This function is primarily covered by the keeper's unit test +// This test just validates the address +func (s *KeeperTestSuite) TestConfirmUndelegation() { + operatorAddress := "operator" + amountToUndelegate := sdkmath.NewInt(100) + tc := s.SetupTestConfirmUndelegation(amountToUndelegate) + + // Store the operator address on the host zone + hostZone := s.MustGetHostZone() + hostZone.OperatorAddressOnStride = "operator" + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + validMsg := types.MsgConfirmUndelegation{ + Operator: operatorAddress, + RecordId: tc.unbondingRecord.Id, + TxHash: ValidTxHashDefault, + } + + invalidMsg := validMsg + invalidMsg.Operator = "invalid_address" + + // confirm the valid tx was successful + _, err := s.GetMsgServer().ConfirmUndelegation(sdk.UnwrapSDKContext(s.Ctx), &validMsg) + s.Require().NoError(err, "no error expected during confirm undelegation") + + // confirm the invalid tx failed because it was not submitted by the operator + _, err = s.GetMsgServer().ConfirmUndelegation(sdk.UnwrapSDKContext(s.Ctx), &invalidMsg) + s.Require().ErrorContains(err, "invalid admin address") +} + +// ---------------------------------------------- +// MsgConfirmUnbondingTokensSweep +// ---------------------------------------------- + +func (s *KeeperTestSuite) SetupUnbondingRecordsAndHostZone() { + s.SetupTestConfirmUnbondingTokens(DefaultClaimFundingAmount) + + // ger relevant variables + safeAddress := s.TestAccs[0].String() + operatorAddress := s.TestAccs[1].String() + hostZone := s.MustGetHostZone() + + // set host zone + hostZone.OperatorAddressOnStride = operatorAddress + hostZone.SafeAddressOnStride = safeAddress + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) +} + +// Verify that ConfirmUnbondingTokenSweep succeeds, and non-admins cannot call it +func (s *KeeperTestSuite) TestConfirmUnbondingTokenSweep() { + safeAddress := s.TestAccs[0].String() + operatorAddress := s.TestAccs[1].String() + nonAdminAddress := s.TestAccs[2].String() + + // Confirm that ConfirmDelegation can be called by the operator address + s.SetupUnbondingRecordsAndHostZone() + MsgConfirmUnbondedTokenSweepOperator := types.MsgConfirmUnbondedTokenSweep{ + Operator: operatorAddress, + RecordId: 6, + TxHash: ValidTxHashNew, + } + _, err := s.GetMsgServer().ConfirmUnbondedTokenSweep(s.Ctx, &MsgConfirmUnbondedTokenSweepOperator) + s.Require().NoError(err, "operator should be able to confirm unbonded token sweep") + + // Confirm that ConfirmDelegation can be called by the safe address + s.SetupUnbondingRecordsAndHostZone() + msgConfirmUnbondedTokenSweepSafe := types.MsgConfirmUnbondedTokenSweep{ + Operator: safeAddress, + RecordId: 6, + TxHash: ValidTxHashNew, + } + _, err = s.GetMsgServer().ConfirmUnbondedTokenSweep(s.Ctx, &msgConfirmUnbondedTokenSweepSafe) + s.Require().NoError(err, "safe should be able to confirm unbonded token sweep") + + // Confirm that ConfirmDelegation cannot be called by a non-admin address + s.SetupUnbondingRecordsAndHostZone() + msgConfirmUnbondedTokenSweepNonAdmin := types.MsgConfirmUnbondedTokenSweep{ + Operator: nonAdminAddress, + RecordId: 6, + TxHash: ValidTxHashNew, + } + _, err = s.GetMsgServer().ConfirmUnbondedTokenSweep(s.Ctx, &msgConfirmUnbondedTokenSweepNonAdmin) + s.Require().ErrorIs(err, types.ErrInvalidAdmin, "non-admin should not be able to confirm unbonded token sweep") +} + +// ---------------------------------------------- +// MsgAdjustDelegatedBalance +// ---------------------------------------------- + +func (s *KeeperTestSuite) TestAdjustDelegatedBalance() { + + safeAddress := "safe" + + // Create the host zone + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + SafeAddressOnStride: safeAddress, + DelegatedBalance: sdk.NewInt(0), + }) + + // we're halting the zone to test that the tx works even when the host zone is halted + s.App.StakedymKeeper.HaltZone(s.Ctx) + + // Call adjust for each test case and confirm the ending delegation + testCases := []struct { + address string + offset sdkmath.Int + endDelegation sdkmath.Int + }{ + {address: "valA", offset: sdkmath.NewInt(10), endDelegation: sdkmath.NewInt(10)}, // 0 + 10 = 10 + {address: "valB", offset: sdkmath.NewInt(-5), endDelegation: sdkmath.NewInt(5)}, // 10 - 5 = 5 + {address: "valC", offset: sdkmath.NewInt(8), endDelegation: sdkmath.NewInt(13)}, // 5 + 8 = 13 + {address: "valD", offset: sdkmath.NewInt(2), endDelegation: sdkmath.NewInt(15)}, // 13 + 2 = 15 + {address: "valE", offset: sdkmath.NewInt(-6), endDelegation: sdkmath.NewInt(9)}, // 15 - 6 = 9 + } + for _, tc := range testCases { + msg := types.MsgAdjustDelegatedBalance{ + Operator: safeAddress, + DelegationOffset: tc.offset, + ValidatorAddress: tc.address, + } + _, err := s.GetMsgServer().AdjustDelegatedBalance(s.Ctx, &msg) + s.Require().NoError(err, "no error expected when adjusting delegated bal properly for %s", tc.address) + + hostZone := s.MustGetHostZone() + s.Require().Equal(tc.endDelegation, hostZone.DelegatedBalance, "delegation after change for %s", tc.address) + } + + // Attempt to call it with an amount that would make it negative, it should fail + _, err := s.GetMsgServer().AdjustDelegatedBalance(s.Ctx, &types.MsgAdjustDelegatedBalance{ + Operator: safeAddress, + DelegationOffset: sdk.NewInt(-10000), + }) + s.Require().ErrorContains(err, "offset would cause the delegated balance to be negative") + + // Attempt to call it from a different address, it should fail + _, err = s.GetMsgServer().AdjustDelegatedBalance(s.Ctx, &types.MsgAdjustDelegatedBalance{ + Operator: s.TestAccs[0].String(), + }) + s.Require().ErrorContains(err, "invalid safe address") + + // Remove the host zone and try again, it should fail + s.App.StakedymKeeper.RemoveHostZone(s.Ctx) + _, err = s.GetMsgServer().AdjustDelegatedBalance(s.Ctx, &types.MsgAdjustDelegatedBalance{}) + s.Require().ErrorContains(err, "host zone not found") + +} + +// ---------------------------------------------- +// MsgUpdateInnerRedemptionRateBounds +// ---------------------------------------------- + +func (s *KeeperTestSuite) TestUpdateInnerRedemptionRateBounds() { + adminAddress, ok := apptesting.GetAdminAddress() + s.Require().True(ok) + + // Register a host zone + zone := types.HostZone{ + ChainId: HostChainId, + // Upper bound 1.5 + MaxRedemptionRate: sdk.NewDec(3).Quo(sdk.NewDec(2)), + // Lower bound 0.9 + MinRedemptionRate: sdk.NewDec(9).Quo(sdk.NewDec(10)), + } + + s.App.StakedymKeeper.SetHostZone(s.Ctx, zone) + // we're halting the zone to test that the tx works even when the host zone is halted + s.App.StakedymKeeper.HaltZone(s.Ctx) + + initialMsg := types.MsgUpdateInnerRedemptionRateBounds{ + Creator: adminAddress, + MinInnerRedemptionRate: sdk.NewDec(90).Quo(sdk.NewDec(100)), + MaxInnerRedemptionRate: sdk.NewDec(105).Quo(sdk.NewDec(100)), + } + + updateMsg := types.MsgUpdateInnerRedemptionRateBounds{ + Creator: adminAddress, + MinInnerRedemptionRate: sdk.NewDec(95).Quo(sdk.NewDec(100)), + MaxInnerRedemptionRate: sdk.NewDec(11).Quo(sdk.NewDec(10)), + } + + invalidMsg := types.MsgUpdateInnerRedemptionRateBounds{ + Creator: adminAddress, + MinInnerRedemptionRate: sdk.NewDec(0), + MaxInnerRedemptionRate: sdk.NewDec(2), + } + + nonAdminMsg := types.MsgUpdateInnerRedemptionRateBounds{ + Creator: "non-admin", + MinInnerRedemptionRate: sdk.NewDec(0), + MaxInnerRedemptionRate: sdk.NewDec(2), + } + + // Set the inner bounds on the host zone for the first time + _, err := s.GetMsgServer().UpdateInnerRedemptionRateBounds(s.Ctx, &initialMsg) + s.Require().NoError(err, "should not throw an error") + + // Confirm the inner bounds were set + zone = s.MustGetHostZone() + s.Require().Equal(initialMsg.MinInnerRedemptionRate, zone.MinInnerRedemptionRate, "min inner redemption rate should be set") + s.Require().Equal(initialMsg.MaxInnerRedemptionRate, zone.MaxInnerRedemptionRate, "max inner redemption rate should be set") + + // Update the inner bounds on the host zone + _, err = s.GetMsgServer().UpdateInnerRedemptionRateBounds(s.Ctx, &updateMsg) + s.Require().NoError(err, "should not throw an error") + + // Confirm the inner bounds were set + zone = s.MustGetHostZone() + s.Require().Equal(updateMsg.MinInnerRedemptionRate, zone.MinInnerRedemptionRate, "min inner redemption rate should be set") + s.Require().Equal(updateMsg.MaxInnerRedemptionRate, zone.MaxInnerRedemptionRate, "max inner redemption rate should be set") + + // Set the inner bounds on the host zone for the first time + _, err = s.GetMsgServer().UpdateInnerRedemptionRateBounds(s.Ctx, &invalidMsg) + s.Require().ErrorContains(err, "invalid host zone redemption rate inner bounds") + + // Attempt to update bounds with a non-admin address, it should fail + _, err = s.GetMsgServer().UpdateInnerRedemptionRateBounds(s.Ctx, &nonAdminMsg) + s.Require().ErrorContains(err, "signer is not an admin") +} + +// ---------------------------------------------- +// MsgResumeHostZone +// ---------------------------------------------- + +// Test cases +// - Zone is not halted +// - Zone is halted - unhalt it +func (s *KeeperTestSuite) TestResumeHostZone() { + // TODO [stdym]: verify denom blacklisting removal works + + adminAddress, ok := apptesting.GetAdminAddress() + s.Require().True(ok) + + zone := types.HostZone{ + ChainId: HostChainId, + RedemptionRate: sdk.NewDec(1), + Halted: false, + NativeTokenDenom: HostNativeDenom, + } + s.App.StakedymKeeper.SetHostZone(s.Ctx, zone) + + msg := types.MsgResumeHostZone{ + Creator: adminAddress, + } + + // TEST 1: Zone is not halted + // Try to unhalt the unhalted zone + _, err := s.GetMsgServer().ResumeHostZone(s.Ctx, &msg) + s.Require().ErrorContains(err, "zone is not halted") + + // Verify the denom is not in the blacklist + blacklist := s.App.RatelimitKeeper.GetAllBlacklistedDenoms(s.Ctx) + s.Require().NotContains(blacklist, StDenom, "denom should not be blacklisted") + + // Confirm the zone is not halted + zone, err = s.App.StakedymKeeper.GetHostZone(s.Ctx) + s.Require().NoError(err, "should not throw an error") + s.Require().False(zone.Halted, "zone should not be halted") + + // TEST 2: Zone is halted + // Halt the zone + s.App.StakedymKeeper.HaltZone(s.Ctx) + + // Verify the denom is in the blacklist + blacklist = s.App.RatelimitKeeper.GetAllBlacklistedDenoms(s.Ctx) + s.Require().Contains(blacklist, StDenom, "denom should be blacklisted") + + // Try to unhalt the halted zone + _, err = s.GetMsgServer().ResumeHostZone(s.Ctx, &msg) + s.Require().NoError(err, "should not throw an error") + + // Confirm the zone is not halted + zone, err = s.App.StakedymKeeper.GetHostZone(s.Ctx) + s.Require().NoError(err, "should not throw an error") + s.Require().False(zone.Halted, "zone should not be halted") + + // Verify the denom is not in the blacklist + blacklist = s.App.RatelimitKeeper.GetAllBlacklistedDenoms(s.Ctx) + s.Require().NotContains(blacklist, StDenom, "denom should not be blacklisted") + + // Attempt to resume with a non-admin address, it should fail + _, err = s.GetMsgServer().ResumeHostZone(s.Ctx, &types.MsgResumeHostZone{ + Creator: "non-admin", + }) + s.Require().ErrorContains(err, "signer is not an admin") +} + +// ---------------------------------------------- +// MsgRefreshRedemptionRate +// ---------------------------------------------- + +func (s *KeeperTestSuite) TestRefreshRedemptionRate() { + safeAddress := "safe" + depositAddress := s.TestAccs[0] + redemptionAddress := s.TestAccs[1] + + // Create host zone with initial redemption rate of 1 + // There will be 1000 delegated tokens, and 500 stTokens + // implying an updated redemption rate of 2 + initialRedemptionRate := sdk.OneDec() + expectedRedemptionRate := sdk.NewDec(2) + + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + DelegatedBalance: sdkmath.NewInt(1000), + RedemptionRate: initialRedemptionRate, + NativeTokenDenom: HostNativeDenom, + NativeTokenIbcDenom: HostIBCDenom, + SafeAddressOnStride: safeAddress, + DepositAddress: depositAddress.String(), + }) + + // Mint 500 stTokens (implying a redemption rate of 2) + s.FundAccount(redemptionAddress, sdk.NewCoin(StDenom, sdkmath.NewInt(500))) + + // Attempt to refresh the rate with a non-safe address, it should fail + _, err := s.GetMsgServer().RefreshRedemptionRate(s.Ctx, &types.MsgRefreshRedemptionRate{ + Creator: "non-admin", + }) + s.Require().ErrorContains(err, "signer is not an admin") + + // Attempt to refresh the rate with the safe address, it should succeed + _, err = s.GetMsgServer().RefreshRedemptionRate(s.Ctx, &types.MsgRefreshRedemptionRate{ + Creator: safeAddress, + }) + s.Require().NoError(err, "no error expected when using safe address") + + // Confirm the redemption rate was updated + hostZone := s.MustGetHostZone() + s.Require().Equal(expectedRedemptionRate, hostZone.RedemptionRate) +} + +// ---------------------------------------------- +// MsgOverwriteDelgationRecord +// ---------------------------------------------- + +func (s *KeeperTestSuite) TestOverwriteDelegationRecord() { + safeAddress := "safe" + recordId := uint64(1) + + // Create a host zone with a safe admin + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + SafeAddressOnStride: safeAddress, + }) + + // Create an initial delegation record, and a record to be overridden + initialDelegationRecord := types.DelegationRecord{ + Id: recordId, + NativeAmount: sdkmath.NewInt(1000), + Status: types.TRANSFER_IN_PROGRESS, + TxHash: "initial-hash", + } + overrideDelegationRecord := types.DelegationRecord{ + Id: recordId, + NativeAmount: sdkmath.NewInt(2000), + Status: types.DELEGATION_QUEUE, + TxHash: "override-hash", + } + s.App.StakedymKeeper.SetDelegationRecord(s.Ctx, initialDelegationRecord) + + // Attempt to override the delegation record from a non-safe address - it should fail + msg := types.MsgOverwriteDelegationRecord{ + Creator: "non-admin", + DelegationRecord: &overrideDelegationRecord, + } + _, err := s.GetMsgServer().OverwriteDelegationRecord(sdk.UnwrapSDKContext(s.Ctx), &msg) + s.Require().ErrorContains(err, "invalid safe address") + + // Check that the record was not updated + recordAfterFailedTx, found := s.App.StakedymKeeper.GetDelegationRecord(s.Ctx, recordId) + s.Require().True(found, "record should not have been removed") + s.Require().Equal(initialDelegationRecord, recordAfterFailedTx, "record should not have been overridden") + + // Attempt to override from the safe address - it should succeed + msg = types.MsgOverwriteDelegationRecord{ + Creator: safeAddress, + DelegationRecord: &overrideDelegationRecord, + } + _, err = s.GetMsgServer().OverwriteDelegationRecord(sdk.UnwrapSDKContext(s.Ctx), &msg) + s.Require().NoError(err, "no error expected when overriding record") + + // Check that the record was updated + recordAfterSuccessfulTx, found := s.App.StakedymKeeper.GetDelegationRecord(s.Ctx, recordId) + s.Require().True(found, "record should not have been removed") + s.Require().Equal(overrideDelegationRecord, recordAfterSuccessfulTx, "record should have been overridden") +} + +// ---------------------------------------------- +// MsgOverwriteUnbondingRecord +// ---------------------------------------------- + +func (s *KeeperTestSuite) TestOverwriteUnbondingRecord() { + safeAddress := "safe" + recordId := uint64(1) + + // Create a host zone with a safe admin + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + SafeAddressOnStride: safeAddress, + }) + + // Create an initial unbonding record, and a record to be overridden + initialUnbondingRecord := types.UnbondingRecord{ + Id: recordId, + NativeAmount: sdkmath.NewInt(1000), + StTokenAmount: sdkmath.NewInt(1000), + Status: types.UNBONDING_IN_PROGRESS, + UnbondingCompletionTimeSeconds: 100, + UndelegationTxHash: "initial-hash-1", + UnbondedTokenSweepTxHash: "initial-hash-2", + } + overrideUnbondingRecord := types.UnbondingRecord{ + Id: recordId, + NativeAmount: sdkmath.NewInt(2000), + StTokenAmount: sdkmath.NewInt(2000), + Status: types.UNBONDED, + UnbondingCompletionTimeSeconds: 200, + UndelegationTxHash: "override-hash-1", + UnbondedTokenSweepTxHash: "override-hash-2", + } + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, initialUnbondingRecord) + + // Attempt to override the unbonding record from a non-safe address - it should fail + msg := types.MsgOverwriteUnbondingRecord{ + Creator: "non-admin", + UnbondingRecord: &overrideUnbondingRecord, + } + _, err := s.GetMsgServer().OverwriteUnbondingRecord(sdk.UnwrapSDKContext(s.Ctx), &msg) + s.Require().ErrorContains(err, "invalid safe address") + + // Check that the record was not updated + recordAfterFailedTx, found := s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, recordId) + s.Require().True(found, "record should not have been removed") + s.Require().Equal(initialUnbondingRecord, recordAfterFailedTx, "record should not have been overridden") + + // Attempt to override from the safe address - it should succeed + msg = types.MsgOverwriteUnbondingRecord{ + Creator: safeAddress, + UnbondingRecord: &overrideUnbondingRecord, + } + _, err = s.GetMsgServer().OverwriteUnbondingRecord(sdk.UnwrapSDKContext(s.Ctx), &msg) + s.Require().NoError(err, "no error expected when overriding record") + + // Check that the record was updated + recordAfterSuccessfulTx, found := s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, recordId) + s.Require().True(found, "record should not have been removed") + s.Require().Equal(overrideUnbondingRecord, recordAfterSuccessfulTx, "record should have been overridden") +} + +// ---------------------------------------------- +// MsgOverwriteRedemptionRecord +// ---------------------------------------------- + +func (s *KeeperTestSuite) TestOverwriteRedemptionRecord() { + safeAddress := "safe" + recordId := uint64(1) + redeemer := "redeemer" + + // Create a host zone with a safe admin + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + SafeAddressOnStride: safeAddress, + }) + + // Create an initial redemption record, and a record to be overridden + initialRedemptionRecord := types.RedemptionRecord{ + UnbondingRecordId: recordId, + Redeemer: redeemer, + NativeAmount: sdkmath.NewInt(1000), + StTokenAmount: sdkmath.NewInt(1000), + } + overrideRedemptionRecord := types.RedemptionRecord{ + UnbondingRecordId: recordId, + Redeemer: redeemer, + NativeAmount: sdkmath.NewInt(2000), + StTokenAmount: sdkmath.NewInt(2000), + } + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, initialRedemptionRecord) + + // Attempt to override the redemption record from a non-safe address - it should fail + msg := types.MsgOverwriteRedemptionRecord{ + Creator: "non-admin", + RedemptionRecord: &overrideRedemptionRecord, + } + _, err := s.GetMsgServer().OverwriteRedemptionRecord(sdk.UnwrapSDKContext(s.Ctx), &msg) + s.Require().ErrorContains(err, "invalid safe address") + + // Check that the record was not updated + recordAfterFailedTx, found := s.App.StakedymKeeper.GetRedemptionRecord(s.Ctx, recordId, redeemer) + s.Require().True(found, "record should not have been removed") + s.Require().Equal(initialRedemptionRecord, recordAfterFailedTx, "record should not have been overridden") + + // Attempt to override from the safe address - it should succeed + msg = types.MsgOverwriteRedemptionRecord{ + Creator: safeAddress, + RedemptionRecord: &overrideRedemptionRecord, + } + _, err = s.GetMsgServer().OverwriteRedemptionRecord(sdk.UnwrapSDKContext(s.Ctx), &msg) + s.Require().NoError(err, "no error expected when overriding record") + + // Check that the record was updated + recordAfterSuccessfulTx, found := s.App.StakedymKeeper.GetRedemptionRecord(s.Ctx, recordId, redeemer) + s.Require().True(found, "record should not have been removed") + s.Require().Equal(overrideRedemptionRecord, recordAfterSuccessfulTx, "record should have been overridden") +} + +// ---------------------------------------------- +// MsgSetOperatorAddress +// ---------------------------------------------- + +// Verify that operator address can be set successfully +func (s *KeeperTestSuite) TestSetOperatorAddress() { + + safeAddress := s.TestAccs[0].String() + operatorAddress := s.TestAccs[1].String() + nonAdminAddress := s.TestAccs[2].String() + + // set the host zone + zone := types.HostZone{ + SafeAddressOnStride: safeAddress, + OperatorAddressOnStride: operatorAddress, + } + s.App.StakedymKeeper.SetHostZone(s.Ctx, zone) + + // Set the operator address, signed by the SAFE address + msgSetOperatorAddress := types.MsgSetOperatorAddress{ + Signer: safeAddress, + Operator: nonAdminAddress, + } + + _, err := s.GetMsgServer().SetOperatorAddress(s.Ctx, &msgSetOperatorAddress) + s.Require().NoError(err, "should not throw an error") + + // Confirm the operator address was updated + zone, err = s.App.StakedymKeeper.GetHostZone(s.Ctx) + s.Require().NoError(err, "should not throw an error") + s.Require().Equal(s.TestAccs[2].String(), zone.OperatorAddressOnStride, "operator address should be set") + + // Confirm the operator address cannot be set by a non-safe address + msgSetOperatorAddressWrongSafe := types.MsgSetOperatorAddress{ + Signer: operatorAddress, + Operator: nonAdminAddress, + } + s.App.StakedymKeeper.SetHostZone(s.Ctx, zone) + _, err = s.GetMsgServer().SetOperatorAddress(s.Ctx, &msgSetOperatorAddressWrongSafe) + s.Require().Error(err, "invalid safe address") +} diff --git a/x/stakedym/keeper/operator_test.go b/x/stakedym/keeper/operator_test.go new file mode 100644 index 0000000000..198acd5fc3 --- /dev/null +++ b/x/stakedym/keeper/operator_test.go @@ -0,0 +1,37 @@ +package keeper_test + +import ( + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// test that the admin address helpers work as expected +func (s *KeeperTestSuite) TestIsAddressHelpers() { + + operatorAddress := s.TestAccs[0].String() + safeAddress := s.TestAccs[1].String() + randomAddress := s.TestAccs[2].String() + + // Create a host zone with an operator and safe + zone := types.HostZone{ + OperatorAddressOnStride: operatorAddress, + SafeAddressOnStride: safeAddress, + } + + s.App.StakedymKeeper.SetHostZone(s.Ctx, zone) + + // Confirm that the operator is an OPERATOR admin + s.Require().NoError(s.App.StakedymKeeper.CheckIsOperatorAddress(s.Ctx, operatorAddress)) + // Confirm that a random address is not an OPERATOR admin + s.Require().Error(s.App.StakedymKeeper.CheckIsOperatorAddress(s.Ctx, randomAddress)) + + // Confirm that the safe is a SAFE admin + s.Require().NoError(s.App.StakedymKeeper.CheckIsSafeAddress(s.Ctx, safeAddress)) + // Confirm that a random address is not a SAFE admin + s.Require().Error(s.App.StakedymKeeper.CheckIsSafeAddress(s.Ctx, randomAddress)) + + // Test SafeOrOperator + s.Require().NoError(s.App.StakedymKeeper.CheckIsSafeOrOperatorAddress(s.Ctx, operatorAddress)) + s.Require().NoError(s.App.StakedymKeeper.CheckIsSafeOrOperatorAddress(s.Ctx, safeAddress)) + s.Require().Error(s.App.StakedymKeeper.CheckIsSafeOrOperatorAddress(s.Ctx, randomAddress)) + +} diff --git a/x/stakedym/keeper/operatorlist.go b/x/stakedym/keeper/operatorlist.go new file mode 100644 index 0000000000..bf74f9b5ee --- /dev/null +++ b/x/stakedym/keeper/operatorlist.go @@ -0,0 +1,59 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// CheckIsOperatorAddress checks if the given address is the operator address +func isOperatorAddress(hostZone types.HostZone, address string) bool { + return address == hostZone.OperatorAddressOnStride +} + +// CheckIsSafeAddress checks if the given address is the safe address +func isSafeAddress(hostZone types.HostZone, address string) bool { + return address == hostZone.SafeAddressOnStride +} + +// CheckIsOperatorAddress checks if the given address is EITHER the safe admin OR operator admin address +func (k Keeper) CheckIsOperatorAddress(ctx sdk.Context, address string) error { + hostZone, err := k.GetHostZone(ctx) + if err != nil { + return err + } + + if !isOperatorAddress(hostZone, address) { + return types.ErrInvalidAdmin.Wrapf("invalid operator address %s", address) + } + + return nil +} + +// CheckIsSafeAddress checks if the given address is the safe admin address +func (k Keeper) CheckIsSafeAddress(ctx sdk.Context, address string) error { + hostZone, err := k.GetHostZone(ctx) + if err != nil { + return err + } + + if !isSafeAddress(hostZone, address) { + return types.ErrInvalidAdmin.Wrapf("invalid safe address %s", address) + } + + return nil +} + +// CheckIsSafeOrOperatorAddress checks if the given address is EITHER the safe admin OR operator admin address +func (k Keeper) CheckIsSafeOrOperatorAddress(ctx sdk.Context, address string) error { + hostZone, err := k.GetHostZone(ctx) + if err != nil { + return err + } + + if !isSafeAddress(hostZone, address) && !isOperatorAddress(hostZone, address) { + return types.ErrInvalidAdmin.Wrapf("invalid admin address %s", address) + } + + return nil +} diff --git a/x/stakedym/keeper/redemption_rate.go b/x/stakedym/keeper/redemption_rate.go new file mode 100644 index 0000000000..40751f3054 --- /dev/null +++ b/x/stakedym/keeper/redemption_rate.go @@ -0,0 +1,139 @@ +package keeper + +import ( + "encoding/json" + "errors" + "fmt" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/utils" + icaoracletypes "github.com/Stride-Labs/stride/v18/x/icaoracle/types" + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// Updates the redemption rate for each host zone +// At a high level, the redemption rate is equal to the amount of native tokens locked divided by the stTokens in existence. +// The equation is broken down further into the following sub-components: +// +// Native Tokens Locked: +// 1. Deposit Account Balance: tokens deposited from liquid stakes, that are still living on Stride +// 2. Undelegated Balance: tokens that are ready to be staked +// (they're either currently in the delegation account or currently being transferred there) +// 3. Delegated Balance: Delegations on the host zone +// +// StToken Amount: +// 1. Total Supply of the stToken +// +// Redemption Rate = (Deposit Account Balance + Undelegated Balance + Delegated Balance) / (stToken Supply) +// +// Note: Reinvested tokens are sent to the deposit account and are automatically included in this formula +func (k Keeper) UpdateRedemptionRate(ctx sdk.Context) error { + k.Logger(ctx).Info(utils.LogWithHostZone(types.DymensionChainId, "Updating redemption rate")) + + hostZone, err := k.GetHostZone(ctx) + if err != nil { + return err + } + + // Get the number of stTokens from the supply + stTokenSupply := k.bankKeeper.GetSupply(ctx, utils.StAssetDenomFromHostZoneDenom(hostZone.NativeTokenDenom)).Amount + if stTokenSupply.IsZero() { + k.Logger(ctx).Info(utils.LogWithHostZone(hostZone.ChainId, + "No st%s in circulation - redemption rate is unchanged", hostZone.NativeTokenDenom)) + return nil + } + + // Get the balance of the deposit address + depositAddress, err := sdk.AccAddressFromBech32(hostZone.DepositAddress) + if err != nil { + return errorsmod.Wrapf(err, "invalid deposit address") + } + depositAccountBalance := k.bankKeeper.GetBalance(ctx, depositAddress, hostZone.NativeTokenIbcDenom) + + // Then add that to the sum of the delegation records to get the undelegated balance + // Delegation records are only created once the tokens leave the deposit address + // and the record is deleted once the tokens are delegated + undelegatedBalance := sdkmath.ZeroInt() + for _, delegationRecord := range k.GetAllActiveDelegationRecords(ctx) { + undelegatedBalance = undelegatedBalance.Add(delegationRecord.NativeAmount) + } + + // Finally, calculated the redemption rate as the native tokens locked divided by the stTokens + nativeTokensLocked := depositAccountBalance.Amount.Add(undelegatedBalance).Add(hostZone.DelegatedBalance) + if !nativeTokensLocked.IsPositive() { + return errors.New("Non-zero stToken supply, yet the zero delegated and undelegated balance") + } + redemptionRate := sdk.NewDecFromInt(nativeTokensLocked).Quo(sdk.NewDecFromInt(stTokenSupply)) + + // Set the old and update redemption rate on the host + hostZone.LastRedemptionRate = hostZone.RedemptionRate + hostZone.RedemptionRate = redemptionRate + k.SetHostZone(ctx, hostZone) + + k.Logger(ctx).Info(utils.LogWithHostZone(types.DymensionChainId, "Redemption rate updated from %v to %v", + hostZone.LastRedemptionRate, hostZone.RedemptionRate)) + k.Logger(ctx).Info(utils.LogWithHostZone(types.DymensionChainId, + "Deposit Account Balance: %v, Undelegated Balance: %v, Delegated Balance: %v, StToken Supply: %v", + depositAccountBalance.Amount, undelegatedBalance, hostZone.DelegatedBalance, stTokenSupply)) + + return nil +} + +// Checks whether the redemption rate has exceeded the inner or outer safety bounds +// and returns an error if so +func (k Keeper) CheckRedemptionRateExceedsBounds(ctx sdk.Context) error { + hostZone, err := k.GetHostZone(ctx) + if err != nil { + return err + } + redemptionRate := hostZone.RedemptionRate + + // Validate the safety bounds (e.g. that the inner is inside the outer) + if err := hostZone.ValidateRedemptionRateBoundsInitalized(); err != nil { + return err + } + + // Check if the redemption rate is outside the outer bounds + if redemptionRate.LT(hostZone.MinRedemptionRate) || redemptionRate.GT(hostZone.MaxRedemptionRate) { + return types.ErrRedemptionRateOutsideSafetyBounds.Wrapf("redemption rate outside outer safety bounds") + } + + // Check if it's outside the inner bounds + if redemptionRate.LT(hostZone.MinInnerRedemptionRate) || redemptionRate.GT(hostZone.MaxInnerRedemptionRate) { + return types.ErrRedemptionRateOutsideSafetyBounds.Wrapf("redemption rate outside inner safety bounds") + } + + return nil +} + +// Pushes a redemption rate update to the ICA oracle +func (k Keeper) PostRedemptionRateToOracles(ctx sdk.Context) error { + if err := k.CheckRedemptionRateExceedsBounds(ctx); err != nil { + return errorsmod.Wrapf(err, "preventing oracle update since redemption rate exceeded bounds") + } + + hostZone, err := k.GetHostZone(ctx) + if err != nil { + return err + } + redemptionRate := hostZone.RedemptionRate + + stDenom := utils.StAssetDenomFromHostZoneDenom(hostZone.NativeTokenDenom) + attributes, err := json.Marshal(icaoracletypes.RedemptionRateAttributes{ + SttokenDenom: stDenom, + }) + if err != nil { + return err + } + + // Metric Key is of format: {stToken}_redemption_rate + metricKey := fmt.Sprintf("%s_%s", stDenom, icaoracletypes.MetricType_RedemptionRate) + metricValue := redemptionRate.String() + metricType := icaoracletypes.MetricType_RedemptionRate + k.icaOracleKeeper.QueueMetricUpdate(ctx, metricKey, metricValue, metricType, string(attributes)) + + return nil +} diff --git a/x/stakedym/keeper/redemption_rate_test.go b/x/stakedym/keeper/redemption_rate_test.go new file mode 100644 index 0000000000..4eb4f2ff00 --- /dev/null +++ b/x/stakedym/keeper/redemption_rate_test.go @@ -0,0 +1,234 @@ +package keeper_test + +import ( + "fmt" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +func (s *KeeperTestSuite) TestUpdateRedemptionRate() { + depositAddress := s.TestAccs[0] + + testCases := []struct { + expectedRedemptionRate sdk.Dec + depositBalance sdkmath.Int + delegatedBalance sdkmath.Int + stTokenSupply sdkmath.Int + delegationRecords []types.DelegationRecord + }{ + { + // Deposit: 250, Undelegated: 500, Delegated: 250, StTokens: 1000 + // (250 + 500 + 250 / 1000) = 1000 / 1000 = 1.0 + expectedRedemptionRate: sdk.MustNewDecFromStr("1.0"), + depositBalance: sdkmath.NewInt(250), + delegatedBalance: sdkmath.NewInt(250), + delegationRecords: []types.DelegationRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(250), Status: types.TRANSFER_IN_PROGRESS}, + {Id: 2, NativeAmount: sdkmath.NewInt(250), Status: types.DELEGATION_QUEUE}, + }, + stTokenSupply: sdkmath.NewInt(1000), + }, + { + // Deposit: 500, Undelegated: 500, Delegated: 250, StTokens: 1000 + // (500 + 500 + 250 / 1000) = 1250 / 1000 = 1.25 + expectedRedemptionRate: sdk.MustNewDecFromStr("1.25"), + depositBalance: sdkmath.NewInt(500), + delegatedBalance: sdkmath.NewInt(250), + delegationRecords: []types.DelegationRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(250), Status: types.TRANSFER_IN_PROGRESS}, + {Id: 2, NativeAmount: sdkmath.NewInt(250), Status: types.DELEGATION_QUEUE}, + }, + stTokenSupply: sdkmath.NewInt(1000), + }, + { + // Deposit: 250, Undelegated: 500, Delegated: 500, StTokens: 1000 + // (500 + 500 + 250 / 1000) = 1250 / 1000 = 1.250 + expectedRedemptionRate: sdk.MustNewDecFromStr("1.25"), + depositBalance: sdkmath.NewInt(250), + delegatedBalance: sdkmath.NewInt(500), + delegationRecords: []types.DelegationRecord{ + {Id: 2, NativeAmount: sdkmath.NewInt(250), Status: types.TRANSFER_IN_PROGRESS}, + {Id: 3, NativeAmount: sdkmath.NewInt(250), Status: types.DELEGATION_QUEUE}, + }, + stTokenSupply: sdkmath.NewInt(1000), + }, + { + // Deposit: 250, Undelegated: 1000, Delegated: 250, StTokens: 1000 + // (250 + 1000 + 250 / 1000) = 1500 / 1000 = 1.5 + expectedRedemptionRate: sdk.MustNewDecFromStr("1.5"), + depositBalance: sdkmath.NewInt(250), + delegatedBalance: sdkmath.NewInt(250), + delegationRecords: []types.DelegationRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(250), Status: types.TRANSFER_IN_PROGRESS}, + {Id: 2, NativeAmount: sdkmath.NewInt(250), Status: types.DELEGATION_QUEUE}, + {Id: 4, NativeAmount: sdkmath.NewInt(250), Status: types.TRANSFER_IN_PROGRESS}, + {Id: 6, NativeAmount: sdkmath.NewInt(250), Status: types.DELEGATION_QUEUE}, + }, + stTokenSupply: sdkmath.NewInt(1000), + }, + { + // Deposit: 250, Undelegated: 500, Delegated: 250, StTokens: 2000 + // (250 + 500 + 250 / 2000) = 1000 / 2000 = 0.5 + expectedRedemptionRate: sdk.MustNewDecFromStr("0.5"), + depositBalance: sdkmath.NewInt(250), + delegatedBalance: sdkmath.NewInt(250), + delegationRecords: []types.DelegationRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(250), Status: types.TRANSFER_IN_PROGRESS}, + {Id: 2, NativeAmount: sdkmath.NewInt(250), Status: types.DELEGATION_QUEUE}, + }, + stTokenSupply: sdkmath.NewInt(2000), + }, + } + + for i, tc := range testCases { + s.Run(fmt.Sprintf("test-%d", i), func() { + s.SetupTest() // reset state + + // Fund the deposit balance + s.FundAccount(depositAddress, sdk.NewCoin(HostIBCDenom, tc.depositBalance)) + + // Create the host zone with the delegated balance and deposit address + initialRedemptionRate := sdk.MustNewDecFromStr("0.999") + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + NativeTokenDenom: HostNativeDenom, + NativeTokenIbcDenom: HostIBCDenom, + DepositAddress: depositAddress.String(), + DelegatedBalance: tc.delegatedBalance, + RedemptionRate: initialRedemptionRate, + }) + + // Set each delegation record + for _, delegationRecord := range tc.delegationRecords { + s.App.StakedymKeeper.SetDelegationRecord(s.Ctx, delegationRecord) + } + + // Add some archive delegation records that should be excluded + // We'll create these by first creating normal records and then removing them + for i := 0; i <= 5; i++ { + id := uint64(i * 1000) + s.App.StakedymKeeper.SetArchivedDelegationRecord(s.Ctx, types.DelegationRecord{Id: id}) + } + + // Mint sttokens for the supply (fund account calls mint) + s.FundAccount(s.TestAccs[1], sdk.NewCoin(StDenom, tc.stTokenSupply)) + + // Update the redemption rate and check that it matches + err := s.App.StakedymKeeper.UpdateRedemptionRate(s.Ctx) + s.Require().NoError(err, "no error expected when calculating redemption rate") + + hostZone := s.MustGetHostZone() + s.Require().Equal(tc.expectedRedemptionRate, hostZone.RedemptionRate, "redemption rate") + + // Check that the last redemption rate was set + s.Require().Equal(initialRedemptionRate, hostZone.LastRedemptionRate, "redemption rate") + }) + + } +} + +func (s *KeeperTestSuite) TestUpdateRedemptionRate_NoTokens() { + depositAddress := s.TestAccs[0] + + // Create the host zone with no delegated balance + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + NativeTokenDenom: HostNativeDenom, + NativeTokenIbcDenom: HostIBCDenom, + DepositAddress: depositAddress.String(), + DelegatedBalance: sdkmath.ZeroInt(), + RedemptionRate: sdk.OneDec(), + }) + + // Check that the update funtion returns nil, since there are no stTokens + err := s.App.StakedymKeeper.UpdateRedemptionRate(s.Ctx) + s.Require().NoError(err, "no error when there are no stTokens") + + // Check that the redemption rate was not updated + hostZone := s.MustGetHostZone() + s.Require().Equal(sdk.OneDec(), hostZone.RedemptionRate, "redemption rate should not have been updated") + + // Mint stTokens + s.FundAccount(s.TestAccs[1], sdk.NewCoin(StDenom, sdkmath.NewInt(1000))) + + // Try to update again, now it should error since there's stTokens but no native tokens + err = s.App.StakedymKeeper.UpdateRedemptionRate(s.Ctx) + s.Require().ErrorContains(err, "Non-zero stToken supply, yet the zero delegated and undelegated balance") +} + +func (s *KeeperTestSuite) TestCheckRedemptionRateExceedsBounds() { + testCases := []struct { + name string + hostZone types.HostZone + exceedsBounds bool + }{ + { + name: "valid bounds", + hostZone: types.HostZone{ + MinRedemptionRate: sdk.MustNewDecFromStr("0.8"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.9"), + RedemptionRate: sdk.MustNewDecFromStr("1.0"), // <-- + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.1"), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2"), + }, + exceedsBounds: false, + }, + { + name: "outside min inner", + hostZone: types.HostZone{ + MinRedemptionRate: sdk.MustNewDecFromStr("0.8"), + RedemptionRate: sdk.MustNewDecFromStr("0.9"), // <-- + MinInnerRedemptionRate: sdk.MustNewDecFromStr("1.0"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.1"), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2"), + }, + exceedsBounds: true, + }, + { + name: "outside max inner", + hostZone: types.HostZone{ + MinRedemptionRate: sdk.MustNewDecFromStr("0.8"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.9"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.0"), + RedemptionRate: sdk.MustNewDecFromStr("1.1"), // <-- + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2"), + }, + exceedsBounds: true, + }, + { + name: "outside min outer", + hostZone: types.HostZone{ + RedemptionRate: sdk.MustNewDecFromStr("0.8"), // <-- + MinRedemptionRate: sdk.MustNewDecFromStr("0.9"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("1.0"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.1"), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2"), + }, + exceedsBounds: true, + }, + { + name: "outside max outer", + hostZone: types.HostZone{ + MinRedemptionRate: sdk.MustNewDecFromStr("0.8"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.9"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.0"), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.1"), + RedemptionRate: sdk.MustNewDecFromStr("1.2"), // <-- + }, + exceedsBounds: true, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.App.StakedymKeeper.SetHostZone(s.Ctx, tc.hostZone) + err := s.App.StakedymKeeper.CheckRedemptionRateExceedsBounds(s.Ctx) + if tc.exceedsBounds { + s.Require().ErrorIs(err, types.ErrRedemptionRateOutsideSafetyBounds) + } else { + s.Require().NoError(err, "no error expected") + } + }) + } +} diff --git a/x/stakedym/keeper/redemption_record.go b/x/stakedym/keeper/redemption_record.go new file mode 100644 index 0000000000..a832ca7401 --- /dev/null +++ b/x/stakedym/keeper/redemption_record.go @@ -0,0 +1,84 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// Writes a redemption record to the store +func (k Keeper) SetRedemptionRecord(ctx sdk.Context, redemptionRecord types.RedemptionRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RedemptionRecordsKeyPrefix) + + recordKey := types.RedemptionRecordKey(redemptionRecord.UnbondingRecordId, redemptionRecord.Redeemer) + recordBz := k.cdc.MustMarshal(&redemptionRecord) + + store.Set(recordKey, recordBz) +} + +// Reads a redemption record from the store +func (k Keeper) GetRedemptionRecord(ctx sdk.Context, unbondingRecordId uint64, address string) (redemptionRecord types.RedemptionRecord, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RedemptionRecordsKeyPrefix) + + recordKey := types.RedemptionRecordKey(unbondingRecordId, address) + recordBz := store.Get(recordKey) + + if len(recordBz) == 0 { + return redemptionRecord, false + } + + k.cdc.MustUnmarshal(recordBz, &redemptionRecord) + return redemptionRecord, true +} + +// Removes a redemption record from the store +func (k Keeper) RemoveRedemptionRecord(ctx sdk.Context, unbondingRecordId uint64, address string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RedemptionRecordsKeyPrefix) + recordKey := types.RedemptionRecordKey(unbondingRecordId, address) + store.Delete(recordKey) +} + +// Returns all redemption records +func (k Keeper) GetAllRedemptionRecords(ctx sdk.Context) (redemptionRecords []types.RedemptionRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RedemptionRecordsKeyPrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + redemptionRecord := types.RedemptionRecord{} + k.cdc.MustUnmarshal(iterator.Value(), &redemptionRecord) + redemptionRecords = append(redemptionRecords, redemptionRecord) + } + + return redemptionRecords +} + +// Returns all redemption records for a given unbonding record +func (k Keeper) GetRedemptionRecordsFromUnbondingId(ctx sdk.Context, unbondingRecordId uint64) (redemptionRecords []types.RedemptionRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.RedemptionRecordsKeyPrefix) + + // Iterate though just the records that match the unbonding record ID prefix + unbondingRecordPrefix := types.IntKey(unbondingRecordId) + iterator := sdk.KVStorePrefixIterator(store, unbondingRecordPrefix) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + redemptionRecord := types.RedemptionRecord{} + k.cdc.MustUnmarshal(iterator.Value(), &redemptionRecord) + redemptionRecords = append(redemptionRecords, redemptionRecord) + } + + return redemptionRecords +} + +// Returns all redemption records for a given address +func (k Keeper) GetRedemptionRecordsFromAddress(ctx sdk.Context, address string) (redemptionRecords []types.RedemptionRecord) { + for _, redemptionRecord := range k.GetAllRedemptionRecords(ctx) { + if redemptionRecord.Redeemer == address { + redemptionRecords = append(redemptionRecords, redemptionRecord) + } + } + return redemptionRecords +} diff --git a/x/stakedym/keeper/redemption_record_test.go b/x/stakedym/keeper/redemption_record_test.go new file mode 100644 index 0000000000..ad0846d736 --- /dev/null +++ b/x/stakedym/keeper/redemption_record_test.go @@ -0,0 +1,155 @@ +package keeper_test + +import ( + "fmt" + + sdkmath "cosmossdk.io/math" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +func (s *KeeperTestSuite) addRedemptionRecords() (redemptionRecords []types.RedemptionRecord) { + for i := 0; i <= 4; i++ { + redemptionRecord := types.RedemptionRecord{ + UnbondingRecordId: uint64(i), + NativeAmount: sdkmath.NewInt(int64(i) * 1000), + StTokenAmount: sdkmath.NewInt(int64(i) * 1000), + Redeemer: fmt.Sprintf("address-%d", i), + } + redemptionRecords = append(redemptionRecords, redemptionRecord) + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, redemptionRecord) + } + return redemptionRecords +} + +func (s *KeeperTestSuite) TestGetRedemptionRecord() { + redemptionRecords := s.addRedemptionRecords() + + for i := 0; i < len(redemptionRecords); i++ { + expectedRecord := redemptionRecords[i] + unbondingRecordId := expectedRecord.UnbondingRecordId + redeemer := expectedRecord.Redeemer + + actualRecord, found := s.App.StakedymKeeper.GetRedemptionRecord(s.Ctx, unbondingRecordId, redeemer) + s.Require().True(found, "redemption record %d should have been found", i) + s.Require().Equal(expectedRecord, actualRecord) + } +} + +func (s *KeeperTestSuite) TestRemoveRedemptionRecord() { + redemptionRecords := s.addRedemptionRecords() + + for removedIndex := 0; removedIndex < len(redemptionRecords); removedIndex++ { + // Remove from removed index + removedRecord := redemptionRecords[removedIndex] + removedUnbondingId := removedRecord.UnbondingRecordId + removedRedeemer := removedRecord.Redeemer + s.App.StakedymKeeper.RemoveRedemptionRecord(s.Ctx, removedUnbondingId, removedRedeemer) + + // Confirm removed + _, found := s.App.StakedymKeeper.GetRedemptionRecord(s.Ctx, removedUnbondingId, removedRedeemer) + s.Require().False(found, "record %d %s should have been removed", removedUnbondingId, removedRedeemer) + + // Check all other records are still there + for checkedIndex := removedIndex + 1; checkedIndex < len(redemptionRecords); checkedIndex++ { + checkedRecord := redemptionRecords[checkedIndex] + checkedUnbondingId := checkedRecord.UnbondingRecordId + checkedRedeemer := checkedRecord.Redeemer + + _, found := s.App.StakedymKeeper.GetRedemptionRecord(s.Ctx, checkedUnbondingId, checkedRedeemer) + s.Require().True(found, "record %d %s should have been removed after %d %s removal", + checkedUnbondingId, checkedRedeemer, removedUnbondingId, removedRedeemer) + } + } +} + +func (s *KeeperTestSuite) TestGetAllRedemptionRecord() { + expectedRecords := s.addRedemptionRecords() + actualRecords := s.App.StakedymKeeper.GetAllRedemptionRecords(s.Ctx) + s.Require().Equal(len(expectedRecords), len(actualRecords), "number of redemption records") + s.Require().ElementsMatch(expectedRecords, actualRecords) +} + +func (s *KeeperTestSuite) TestGetAllRedemptionRecordsFromUnbondingId() { + // Define a set of redemption records across different unbonding record IDs + unbondingIdToRecords := map[uint64][]types.RedemptionRecord{ + 1: { + {UnbondingRecordId: 1, Redeemer: "address-A"}, + {UnbondingRecordId: 1, Redeemer: "address-B"}, + {UnbondingRecordId: 1, Redeemer: "address-C"}, + }, + 2: { + {UnbondingRecordId: 2, Redeemer: "address-D"}, + {UnbondingRecordId: 2, Redeemer: "address-E"}, + {UnbondingRecordId: 2, Redeemer: "address-F"}, + }, + 3: { + {UnbondingRecordId: 3, Redeemer: "address-G"}, + {UnbondingRecordId: 3, Redeemer: "address-H"}, + {UnbondingRecordId: 3, Redeemer: "address-I"}, + }, + } + + // Store all the redemption records + for _, redemptionRecords := range unbondingIdToRecords { + for _, redemptionRecord := range redemptionRecords { + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, redemptionRecord) + } + } + + // Lookup records by unbonding Id and confirm it matches the expected list + for unbondingRecordId, expectedRedemptionRecords := range unbondingIdToRecords { + actualRedemptionRecords := s.App.StakedymKeeper.GetRedemptionRecordsFromUnbondingId(s.Ctx, unbondingRecordId) + s.Require().Equal(len(expectedRedemptionRecords), len(actualRedemptionRecords), + "number of redemption records for unbonding id %d", unbondingRecordId) + + for i, expectedRecord := range expectedRedemptionRecords { + actualRecord := actualRedemptionRecords[i] + s.Require().Equal(expectedRecord.Redeemer, actualRecord.Redeemer, "redemption record address") + s.Require().Equal(unbondingRecordId, actualRecord.UnbondingRecordId, + "redemption record unbonding ID for %s", expectedRecord.Redeemer) + } + } +} + +func (s *KeeperTestSuite) TestGetRedemptionRecordsFromAddress() { + // Define a set of redemption records across different addresses + unbondingAddressToRecords := map[string][]types.RedemptionRecord{ + "address-A": { + {UnbondingRecordId: 1, Redeemer: "address-A"}, + {UnbondingRecordId: 2, Redeemer: "address-A"}, + {UnbondingRecordId: 3, Redeemer: "address-A"}, + }, + "address-B": { + {UnbondingRecordId: 4, Redeemer: "address-B"}, + {UnbondingRecordId: 5, Redeemer: "address-B"}, + {UnbondingRecordId: 6, Redeemer: "address-B"}, + }, + "address-C": { + {UnbondingRecordId: 7, Redeemer: "address-C"}, + {UnbondingRecordId: 8, Redeemer: "address-C"}, + {UnbondingRecordId: 9, Redeemer: "address-C"}, + }, + } + + // Store all the redemption records + for _, redemptionRecords := range unbondingAddressToRecords { + for _, redemptionRecord := range redemptionRecords { + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, redemptionRecord) + } + } + + // Lookup records by address and confirm it matches the expected list + for expectedAddress, expectedRedemptionRecords := range unbondingAddressToRecords { + actualRedemptionRecords := s.App.StakedymKeeper.GetRedemptionRecordsFromAddress(s.Ctx, expectedAddress) + s.Require().Equal(len(expectedRedemptionRecords), len(actualRedemptionRecords), + "number of redemption records for address %d", expectedAddress) + + for i, expectedRecord := range expectedRedemptionRecords { + actualRecord := actualRedemptionRecords[i] + s.Require().Equal(expectedAddress, actualRecord.Redeemer, "redemption record address") + s.Require().Equal(expectedRecord.UnbondingRecordId, actualRecord.UnbondingRecordId, + "redemption record unbonding ID for %s", expectedRecord.Redeemer) + } + } +} diff --git a/x/stakedym/keeper/slash_record.go b/x/stakedym/keeper/slash_record.go new file mode 100644 index 0000000000..6f13a5148c --- /dev/null +++ b/x/stakedym/keeper/slash_record.go @@ -0,0 +1,56 @@ +package keeper + +import ( + "encoding/binary" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// Writes a slash record to the store +func (k Keeper) SetSlashRecord(ctx sdk.Context, slashRecord types.SlashRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.SlashRecordsKeyPrefix) + + key := types.IntKey(slashRecord.Id) + value := k.cdc.MustMarshal(&slashRecord) + + store.Set(key, value) +} + +// Returns all slash records +func (k Keeper) GetAllSlashRecords(ctx sdk.Context) (slashRecords []types.SlashRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.SlashRecordsKeyPrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + allSlashRecords := []types.SlashRecord{} + for ; iterator.Valid(); iterator.Next() { + + slashRecord := types.SlashRecord{} + k.cdc.MustUnmarshal(iterator.Value(), &slashRecord) + allSlashRecords = append(allSlashRecords, slashRecord) + } + + return allSlashRecords +} + +// Increments the current slash record ID and returns the new ID +func (k Keeper) IncrementSlashRecordId(ctx sdk.Context) uint64 { + store := ctx.KVStore(k.storeKey) + currentIdBz := store.Get(types.SlashRecordStoreKeyPrefix) + + // return 1 if there's nothing in the store yet + currentId := uint64(1) + if len(currentIdBz) != 0 { + currentId = binary.BigEndian.Uint64(currentIdBz) + } + + // Increment the ID + nextId := currentId + 1 + store.Set(types.SlashRecordStoreKeyPrefix, types.IntKey(nextId)) + + return nextId +} diff --git a/x/stakedym/keeper/slash_record_test.go b/x/stakedym/keeper/slash_record_test.go new file mode 100644 index 0000000000..d501ac034c --- /dev/null +++ b/x/stakedym/keeper/slash_record_test.go @@ -0,0 +1,73 @@ +package keeper_test + +import ( + math "cosmossdk.io/math" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// Helper function to create and set 5 slashRecord objects with various attributes +func (s *KeeperTestSuite) createAndSetSlashRecords() []types.SlashRecord { + SlashRecords := []types.SlashRecord{} + valAddresses := []string{"valA", "valB", "valC", "valD", "valE"} + offsets := []math.Int{ + math.NewInt(-1), + math.NewInt(0), + math.NewInt(1), + math.NewInt(2), + math.NewInt(10), + } + for i := 0; i < 5; i++ { + slashRecord := types.SlashRecord{ + Id: uint64(i), + Time: uint64(s.Ctx.BlockTime().Unix()), + NativeAmount: offsets[i], + ValidatorAddress: valAddresses[i], + } + SlashRecords = append(SlashRecords, slashRecord) + s.App.StakedymKeeper.SetSlashRecord(s.Ctx, slashRecord) + } + return SlashRecords +} + +func (s *KeeperTestSuite) TestGetAllSlashRecords() { + expectedSlashRecords := s.createAndSetSlashRecords() + actualSlashRecords := s.App.StakedymKeeper.GetAllSlashRecords(s.Ctx) + s.Require().Len(actualSlashRecords, len(expectedSlashRecords), "number of SlashRecords") + s.Require().ElementsMatch(expectedSlashRecords, actualSlashRecords, "contents of SlashRecords") +} + +func (s *KeeperTestSuite) TestSetSlashRecord() { + expectedSlashRecords := s.createAndSetSlashRecords() + // make a slash record with a NEW ID and set it, then make sure a new record was added + newSlashRecord := types.SlashRecord{ + Id: uint64(5), + Time: uint64(s.Ctx.BlockTime().Unix()), + NativeAmount: math.NewInt(1), + ValidatorAddress: "valZ", + } + s.App.StakedymKeeper.SetSlashRecord(s.Ctx, newSlashRecord) + actualSlashRecords := s.App.StakedymKeeper.GetAllSlashRecords(s.Ctx) + s.Require().Len(actualSlashRecords, len(expectedSlashRecords)+1, "number of SlashRecords with new slashRecord added") + s.Require().Equal(newSlashRecord, actualSlashRecords[5], "contents of newly added SlashRecord") + + // make a slash record with an existing ID and set it, then make sure no new record was added (just existing modified) + overwriteSlashRecord := types.SlashRecord{ + Id: uint64(0), + Time: uint64(s.Ctx.BlockTime().Unix()), + NativeAmount: math.NewInt(1), + ValidatorAddress: "valZ", + } + s.App.StakedymKeeper.SetSlashRecord(s.Ctx, overwriteSlashRecord) + actualSlashRecords = s.App.StakedymKeeper.GetAllSlashRecords(s.Ctx) + s.Require().Len(actualSlashRecords, len(expectedSlashRecords)+1, "number of SlashRecords same as before overwriting") + s.Require().Equal(overwriteSlashRecord, actualSlashRecords[0], "contents of newly added SlashRecord") +} + +func (s *KeeperTestSuite) TestIncrementSlashRecordId() { + prevSlashRecordId := s.App.StakedymKeeper.IncrementSlashRecordId(s.Ctx) + currSlashRecordId := s.App.StakedymKeeper.IncrementSlashRecordId(s.Ctx) + nextSlashRecordId := s.App.StakedymKeeper.IncrementSlashRecordId(s.Ctx) + s.Require().Equal(prevSlashRecordId+1, currSlashRecordId, "incremented slash record id (tests incrementing)") + s.Require().Equal(currSlashRecordId+1, nextSlashRecordId, "incremented slash record id again (test storing incremented val)") +} diff --git a/x/stakedym/keeper/transfer_callback.go b/x/stakedym/keeper/transfer_callback.go new file mode 100644 index 0000000000..2929cb32a2 --- /dev/null +++ b/x/stakedym/keeper/transfer_callback.go @@ -0,0 +1,69 @@ +package keeper + +import ( + "encoding/binary" + "strings" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// Stores the record ID for a pending outbound transfer of native tokens +func (k Keeper) SetTransferInProgressRecordId(ctx sdk.Context, channelId string, sequence uint64, recordId uint64) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.TransferInProgressRecordIdKeyPrefix) + + recordIdKey := types.TransferInProgressRecordKey(channelId, sequence) + recordIdBz := types.IntKey(recordId) + + store.Set(recordIdKey, recordIdBz) +} + +// Gets the record ID for a pending outbound transfer of native tokens +func (k Keeper) GetTransferInProgressRecordId(ctx sdk.Context, channelId string, sequence uint64) (recordId uint64, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.TransferInProgressRecordIdKeyPrefix) + + recordIdKey := types.TransferInProgressRecordKey(channelId, sequence) + recordIdBz := store.Get(recordIdKey) + + if len(recordIdBz) == 0 { + return 0, false + } + + recordId = binary.BigEndian.Uint64(recordIdBz) + return recordId, true +} + +// Remove the record ID for a pending outbound transfer of native tokens +// Happens after the packet acknowledement comes back to stride +func (k Keeper) RemoveTransferInProgressRecordId(ctx sdk.Context, channelId string, sequence uint64) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.TransferInProgressRecordIdKeyPrefix) + recordIdKey := types.TransferInProgressRecordKey(channelId, sequence) + store.Delete(recordIdKey) +} + +// Get all pending transfers +func (k Keeper) GetAllTransferInProgressId(ctx sdk.Context) (transferInProgressRecordIds []types.TransferInProgressRecordIds) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.TransferInProgressRecordIdKeyPrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + key := iterator.Key() + + channelId := string(key[:types.ChannelIdBufferFixedLength]) + channelId = strings.TrimRight(channelId, "\x00") // removes null bytes from suffix + sequence := binary.BigEndian.Uint64(key[types.ChannelIdBufferFixedLength:]) + recordId := binary.BigEndian.Uint64(iterator.Value()) + + transferInProgressRecordIds = append(transferInProgressRecordIds, types.TransferInProgressRecordIds{ + ChannelId: channelId, + Sequence: sequence, + RecordId: recordId, + }) + } + + return transferInProgressRecordIds +} diff --git a/x/stakedym/keeper/transfer_callback_test.go b/x/stakedym/keeper/transfer_callback_test.go new file mode 100644 index 0000000000..c8d8c2d60c --- /dev/null +++ b/x/stakedym/keeper/transfer_callback_test.go @@ -0,0 +1,96 @@ +package keeper_test + +import ( + "fmt" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +type transferData struct { + channelId string + sequence uint64 + recordId uint64 +} + +func (s *KeeperTestSuite) addTransferRecords() (transferRecords []transferData) { + for i := 0; i <= 4; i++ { + transferRecord := transferData{ + channelId: fmt.Sprintf("channel-%d", i), + sequence: uint64(i), + recordId: uint64(i), + } + transferRecords = append(transferRecords, transferRecord) + s.App.StakedymKeeper.SetTransferInProgressRecordId(s.Ctx, transferRecord.channelId, + transferRecord.sequence, transferRecord.recordId) + } + return transferRecords +} + +func (s *KeeperTestSuite) TestGetTransferInProgressRecordId() { + transferRecords := s.addTransferRecords() + + for i := 0; i < len(transferRecords); i++ { + expectedRecordId := transferRecords[i].recordId + channelId := transferRecords[i].channelId + sequence := transferRecords[i].sequence + + actualRecordId, found := s.App.StakedymKeeper.GetTransferInProgressRecordId(s.Ctx, channelId, sequence) + s.Require().True(found, "redemption record %d should have been found", i) + s.Require().Equal(expectedRecordId, actualRecordId) + } +} + +func (s *KeeperTestSuite) TestRemoveTransferInProgressRecordId() { + transferRecords := s.addTransferRecords() + + for removedIndex := 0; removedIndex < len(transferRecords); removedIndex++ { + // Remove recordId at removed index from store + removedRecordId := transferRecords[removedIndex].recordId + removedChannelId := transferRecords[removedIndex].channelId + removedSequence := transferRecords[removedIndex].sequence + s.App.StakedymKeeper.RemoveTransferInProgressRecordId(s.Ctx, removedChannelId, removedSequence) + + // Confirm removed + _, found := s.App.StakedymKeeper.GetTransferInProgressRecordId(s.Ctx, removedChannelId, removedSequence) + s.Require().False(found, "recordId %d for %s %d should have been removed", removedRecordId, removedChannelId, removedSequence) + + // Check all other recordIds are still there + for checkedIndex := removedIndex + 1; checkedIndex < len(transferRecords); checkedIndex++ { + checkedRecordId := transferRecords[checkedIndex].recordId + checkedChannelId := transferRecords[checkedIndex].channelId + checkedSequence := transferRecords[checkedIndex].sequence + + _, found := s.App.StakedymKeeper.GetTransferInProgressRecordId(s.Ctx, checkedChannelId, checkedSequence) + s.Require().True(found, "recordId %d with %s %d should have been found after %d with %s %d removal", + checkedRecordId, checkedChannelId, checkedSequence, removedRecordId, removedChannelId, removedSequence) + } + } +} + +func (s *KeeperTestSuite) TestGetAllTransferInProgressIds() { + // Store 5 packets across two channels + expectedTransfers := []types.TransferInProgressRecordIds{} + for _, channelId := range []string{"channel-0", "channel-1"} { + for sequence := uint64(0); sequence < 5; sequence++ { + recordId := sequence * 100 + s.App.StakedymKeeper.SetTransferInProgressRecordId(s.Ctx, channelId, sequence, recordId) + expectedTransfers = append(expectedTransfers, types.TransferInProgressRecordIds{ + ChannelId: channelId, + Sequence: sequence, + RecordId: recordId, + }) + } + } + + // Check that each transfer is found + for _, channelId := range []string{"channel-0", "channel-1"} { + for sequence := uint64(0); sequence < 5; sequence++ { + _, found := s.App.StakedymKeeper.GetTransferInProgressRecordId(s.Ctx, channelId, sequence) + s.Require().True(found, "transfer should have been found - channel %s, sequence: %d", channelId, sequence) + } + } + + // Check lookup of all transfers + actualTransfers := s.App.StakedymKeeper.GetAllTransferInProgressId(s.Ctx) + s.Require().ElementsMatch(expectedTransfers, actualTransfers, "all transfers") +} diff --git a/x/stakedym/keeper/unbonding.go b/x/stakedym/keeper/unbonding.go new file mode 100644 index 0000000000..2e76833833 --- /dev/null +++ b/x/stakedym/keeper/unbonding.go @@ -0,0 +1,411 @@ +package keeper + +import ( + "fmt" + "time" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/Stride-Labs/stride/v18/utils" + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// Takes custody of staked tokens in an escrow account, updates the current +// accumulating UnbondingRecord with the amount taken, and creates or updates +// the RedemptionRecord for this user +func (k Keeper) RedeemStake(ctx sdk.Context, redeemer string, stTokenAmount sdkmath.Int) (nativeToken sdk.Coin, err error) { + // Validate Basic already has ensured redeemer is legal address, stTokenAmount is above min threshold + + // Check HostZone exists, has legal redemption address for escrow, is not halted, has RR in bounds + hostZone, err := k.GetUnhaltedHostZone(ctx) + if err != nil { + return nativeToken, err + } + + escrowAccount, err := sdk.AccAddressFromBech32(hostZone.RedemptionAddress) + if err != nil { + return nativeToken, errorsmod.Wrapf(err, "could not bech32 decode redemption address %s on stride", hostZone.RedemptionAddress) + } + + err = k.CheckRedemptionRateExceedsBounds(ctx) + if err != nil { + return nativeToken, err + } + + // Get the current accumulating UnbondingRecord + accUnbondingRecord, err := k.GetAccumulatingUnbondingRecord(ctx) + if err != nil { + return nativeToken, err + } + + // Check redeemer owns at least stTokenAmount of stadym + stDenom := utils.StAssetDenomFromHostZoneDenom(hostZone.NativeTokenDenom) + redeemerAccount, err := sdk.AccAddressFromBech32(redeemer) + if err != nil { + return nativeToken, errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", redeemer) + } + + balance := k.bankKeeper.GetBalance(ctx, redeemerAccount, stDenom) + if balance.Amount.LT(stTokenAmount) { + return nativeToken, errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, + "wallet balance of stTIA is lower than redemption amount. %v < %v: ", balance.Amount, stTokenAmount) + } + + // Estimate a placeholder native amount with current RedemptionRate + // this estimate will be updated when the Undelegation record is finalized + nativeAmount := sdk.NewDecFromInt(stTokenAmount).Mul(hostZone.RedemptionRate).RoundInt() + if nativeAmount.GT(hostZone.DelegatedBalance) { + return nativeToken, errorsmod.Wrapf(types.ErrUnbondAmountToLarge, + "cannot unstake an amount g.t. total staked balance: %v > %v", nativeAmount, hostZone.DelegatedBalance) + } + + // Update the accumulating UnbondingRecord with the undelegation amounts + accUnbondingRecord.StTokenAmount = accUnbondingRecord.StTokenAmount.Add(stTokenAmount) + accUnbondingRecord.NativeAmount = accUnbondingRecord.NativeAmount.Add(nativeAmount) + + // Update or create the RedemptionRecord for this redeemer + redemptionRecord, userHasActiveRedemptionRecord := k.GetRedemptionRecord(ctx, accUnbondingRecord.Id, redeemer) + if userHasActiveRedemptionRecord { + // Already active RedemptionRecord found for this redeemer this epoch so will update it + redemptionRecord.StTokenAmount = redemptionRecord.StTokenAmount.Add(stTokenAmount) + redemptionRecord.NativeAmount = redemptionRecord.NativeAmount.Add(nativeAmount) + } else { + // Creating new RedemptionRecord for this redeemer this epoch + redemptionRecord = types.RedemptionRecord{ + UnbondingRecordId: accUnbondingRecord.Id, + Redeemer: redeemer, + NativeAmount: nativeAmount, + StTokenAmount: stTokenAmount, + } + } + nativeToken = sdk.NewCoin(hostZone.NativeTokenDenom, nativeAmount) // Should it be NativeTokenIbcDenom? + + // Escrow user's stTIA balance before setting either record in the store to verify everything worked + redeemCoins := sdk.NewCoins(sdk.NewCoin(stDenom, stTokenAmount)) + err = k.bankKeeper.SendCoins(ctx, redeemerAccount, escrowAccount, redeemCoins) + if err != nil { + return nativeToken, errorsmod.Wrapf(err, "couldn't send %v stadym. err: %s", stTokenAmount, err.Error()) + } + + // Now that escrow succeeded, actually set the updated records in the store + k.SetUnbondingRecord(ctx, accUnbondingRecord) + k.SetRedemptionRecord(ctx, redemptionRecord) + + EmitSuccessfulRedeemStakeEvent(ctx, redeemer, hostZone, nativeAmount, stTokenAmount) + return nativeToken, nil +} + +// Freezes the ACCUMULATING record by changing the status to UNBONDING_QUEUE +// and updating the native token amounts on the unbonding and redemption records +func (k Keeper) PrepareUndelegation(ctx sdk.Context, epochNumber uint64) error { + k.Logger(ctx).Info(utils.LogWithHostZone(types.DymensionChainId, "Preparing undelegation for epoch %d", epochNumber)) + + // Get the redemption record from the host zone (to calculate the native tokens) + hostZone, err := k.GetUnhaltedHostZone(ctx) + if err != nil { + return err + } + redemptionRate := hostZone.RedemptionRate + + // Get the one accumulating record that has the redemptions for the past epoch + unbondingRecord, err := k.GetAccumulatingUnbondingRecord(ctx) + if err != nil { + return err + } + + // Create the new accumulating record for this epoch + newUnbondingRecord := types.UnbondingRecord{ + Id: epochNumber, + Status: types.ACCUMULATING_REDEMPTIONS, + StTokenAmount: sdkmath.ZeroInt(), + NativeAmount: sdkmath.ZeroInt(), + } + if err := k.SafelySetUnbondingRecord(ctx, newUnbondingRecord); err != nil { + return err + } + + // Update the number of native tokens for all the redemption records + // Keep track of the total for the unbonding record + totalNativeTokens := sdkmath.ZeroInt() + for _, redemptionRecord := range k.GetRedemptionRecordsFromUnbondingId(ctx, unbondingRecord.Id) { + nativeAmount := sdk.NewDecFromInt(redemptionRecord.StTokenAmount).Mul(redemptionRate).RoundInt() + redemptionRecord.NativeAmount = nativeAmount + k.SetRedemptionRecord(ctx, redemptionRecord) + totalNativeTokens = totalNativeTokens.Add(nativeAmount) + } + + // If there were no unbondings this epoch, archive the current record + if totalNativeTokens.IsZero() { + k.ArchiveUnbondingRecord(ctx, unbondingRecord) + return nil + } + + // Update the total on the record and change the status to QUEUE + unbondingRecord.Status = types.UNBONDING_QUEUE + unbondingRecord.NativeAmount = totalNativeTokens + k.SetUnbondingRecord(ctx, unbondingRecord) + + return nil +} + +// Confirms that an undelegation has been completed on the host zone +// Updates the record status to UNBONDING_IN_PROGRESS, decrements the delegated balance and burns stTokens +func (k Keeper) ConfirmUndelegation(ctx sdk.Context, recordId uint64, txHash string, sender string) (err error) { + // grab unbonding record, verify it's in the right state, and no tx hash has been submitted yet + record, found := k.GetUnbondingRecord(ctx, recordId) + if !found { + return errorsmod.Wrapf(types.ErrUnbondingRecordNotFound, "couldn't find unbonding record with id: %d", recordId) + } + if record.Status != types.UNBONDING_QUEUE { + return errorsmod.Wrapf(types.ErrInvalidUnbondingRecord, "unbonding record with id: %d is not ready to be undelegated", recordId) + } + if record.UndelegationTxHash != "" { + return errorsmod.Wrapf(types.ErrInvalidUnbondingRecord, "unbonding record with id: %d already has undelegation tx hash set", recordId) + } + if record.UnbondedTokenSweepTxHash != "" { + return errorsmod.Wrapf(types.ErrInvalidUnbondingRecord, "unbonding record with id: %d already has token sweep tx hash set", recordId) + } + + // if there are no tokens to unbond (or negative on the record): throw an error! + noTokensUnbondedOrNegative := record.NativeAmount.LTE(sdk.ZeroInt()) || record.StTokenAmount.LTE(sdk.ZeroInt()) + if noTokensUnbondedOrNegative { + return errorsmod.Wrapf(types.ErrInvalidUnbondingRecord, "unbonding record with id: %d has no tokens to unbond (or negative)", recordId) + } + + // Note: we're intentionally not checking that the host zone is halted, because we still want to process this tx in that case + hostZone, err := k.GetHostZone(ctx) + if err != nil { + return err + } + + // sanity check: store down the stToken supply and DelegatedBalance for checking against after burn + stDenom := utils.StAssetDenomFromHostZoneDenom(hostZone.NativeTokenDenom) + stTokenSupplyBefore := k.bankKeeper.GetSupply(ctx, stDenom).Amount + delegatedBalanceBefore := hostZone.DelegatedBalance + + // update the record's txhash, status, and unbonding completion time + unbondingLength := time.Duration(hostZone.UnbondingPeriodSeconds) * time.Second // 21 days + unbondingCompletionTime := uint64(ctx.BlockTime().Add(unbondingLength).Unix()) // now + 21 days + + record.UndelegationTxHash = txHash + record.Status = types.UNBONDING_IN_PROGRESS + record.UnbondingCompletionTimeSeconds = unbondingCompletionTime + k.SetUnbondingRecord(ctx, record) + + // update host zone struct's delegated balance + amountAddedToDelegation := record.NativeAmount + newDelegatedBalance := hostZone.DelegatedBalance.Sub(amountAddedToDelegation) + + // sanity check: if the new balance is negative, throw an error + if newDelegatedBalance.IsNegative() { + return errorsmod.Wrapf(types.ErrNegativeNotAllowed, "host zone's delegated balance would be negative after undelegation") + } + hostZone.DelegatedBalance = newDelegatedBalance + k.SetHostZone(ctx, hostZone) + + // burn the corresponding stTokens from the redemptionAddress + stTokensToBurn := sdk.NewCoins(sdk.NewCoin(stDenom, record.StTokenAmount)) + if err := k.BurnRedeemedStTokens(ctx, stTokensToBurn, hostZone.RedemptionAddress); err != nil { + return errorsmod.Wrapf(err, "unable to burn stTokens in ConfirmUndelegation") + } + + // sanity check: check that (DelegatedBalance increment / stToken supply decrement) is within outer bounds + if err := k.VerifyImpliedRedemptionRateFromUnbonding(ctx, stTokenSupplyBefore, delegatedBalanceBefore); err != nil { + return errorsmod.Wrap(err, "ratio of delegation change to burned tokens exceeds redemption rate bounds") + } + + EmitSuccessfulConfirmUndelegationEvent(ctx, recordId, record.NativeAmount, txHash, sender) + return nil +} + +// Burn stTokens from the redemption account +// - this requires sending them to an module account first, then burning them from there. +// - we use the stakedym module account +func (k Keeper) BurnRedeemedStTokens(ctx sdk.Context, stTokensToBurn sdk.Coins, redemptionAddress string) error { + acctAddressRedemption, err := sdk.AccAddressFromBech32(redemptionAddress) + if err != nil { + return fmt.Errorf("could not bech32 decode address %s", redemptionAddress) + } + + // send tokens from the EOA to the stakedym module account + err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, acctAddressRedemption, types.ModuleName, stTokensToBurn) + if err != nil { + return errorsmod.Wrapf(err, "could not send coins from account %s to module %s. err: %s", redemptionAddress, types.ModuleName, err) + } + + // burn the stTokens from the stakedym module account + err = k.bankKeeper.BurnCoins(ctx, types.ModuleName, stTokensToBurn) + if err != nil { + return errorsmod.Wrapf(err, "couldn't burn %v tokens in module account", stTokensToBurn) + } + + return nil +} + +// Sanity check helper for checking diffs on delegated balance and stToken supply are within outer RR bounds +func (k Keeper) VerifyImpliedRedemptionRateFromUnbonding(ctx sdk.Context, stTokenSupplyBefore sdkmath.Int, delegatedBalanceBefore sdkmath.Int) error { + hostZoneAfter, err := k.GetHostZone(ctx) + if err != nil { + return types.ErrHostZoneNotFound + } + stDenom := utils.StAssetDenomFromHostZoneDenom(hostZoneAfter.NativeTokenDenom) + + // grab the delegated balance and token supply after the burn + delegatedBalanceAfter := hostZoneAfter.DelegatedBalance + stTokenSupplyAfter := k.bankKeeper.GetSupply(ctx, stDenom).Amount + + // calculate the delta for both the delegated balance and stToken burn + delegatedBalanceDecremented := delegatedBalanceBefore.Sub(delegatedBalanceAfter) + stTokenSupplyBurned := stTokenSupplyBefore.Sub(stTokenSupplyAfter) + + // It shouldn't be possible for this to be zero, but this will prevent a division by zero error + if stTokenSupplyBurned.IsZero() { + return types.ErrDivisionByZero + } + + // calculate the ratio of delegated balance change to stToken burn - it should be close to the redemption rate + ratio := sdk.NewDecFromInt(delegatedBalanceDecremented).Quo(sdk.NewDecFromInt(stTokenSupplyBurned)) + + // check ratio against bounds + if ratio.LT(hostZoneAfter.MinRedemptionRate) || ratio.GT(hostZoneAfter.MaxRedemptionRate) { + return types.ErrRedemptionRateOutsideSafetyBounds + } + return nil +} + +// Checks for any unbonding records that have finished unbonding, +// identified by having status UNBONDING_IN_PROGRESS and an +// unbonding that's older than the current time. +// Records are annotated with a new status UNBONDED +func (k Keeper) MarkFinishedUnbondings(ctx sdk.Context) { + for _, unbondingRecord := range k.GetAllUnbondingRecordsByStatus(ctx, types.UNBONDING_IN_PROGRESS) { + if ctx.BlockTime().Unix() > int64(unbondingRecord.UnbondingCompletionTimeSeconds) { + unbondingRecord.Status = types.UNBONDED + k.SetUnbondingRecord(ctx, unbondingRecord) + } + } +} + +// Confirms that unbonded tokens have been sent back to stride and marks the unbonding record CLAIMABLE +func (k Keeper) ConfirmUnbondedTokenSweep(ctx sdk.Context, recordId uint64, txHash string, sender string) (err error) { + // grab unbonding record and verify the record is ready to be swept, and has not been swept yet + record, found := k.GetUnbondingRecord(ctx, recordId) + if !found { + return errorsmod.Wrapf(types.ErrUnbondingRecordNotFound, "couldn't find unbonding record with id: %d", recordId) + } + if record.Status != types.UNBONDED { + return errorsmod.Wrapf(types.ErrInvalidUnbondingRecord, "unbonding record with id: %d is not ready to be swept", recordId) + } + if record.UnbondedTokenSweepTxHash != "" { + return errorsmod.Wrapf(types.ErrInvalidUnbondingRecord, "unbonding record with id: %d already has a tx hash set", recordId) + } + + // verify amount to sweep is positive + unbondingRecordIsNonPositive := !record.NativeAmount.IsPositive() || !record.StTokenAmount.IsPositive() + if unbondingRecordIsNonPositive { + return errorsmod.Wrapf(types.ErrInvalidUnbondingRecord, "unbonding record with id: %d has non positive amount to sweep", recordId) + } + + // grab claim address from host zone + // note: we're intentionally not checking that the host zone is halted, because we still want to process this tx in that case + hostZone, err := k.GetHostZone(ctx) + if err != nil { + return err + } + claimAddress, err := sdk.AccAddressFromBech32(hostZone.ClaimAddress) + if err != nil { + return err + } + + // verify the claim address has the same or more tokens than the record (necessary condition if sweep was successful) + claimAddressBalance := k.bankKeeper.GetBalance(ctx, claimAddress, hostZone.NativeTokenIbcDenom) + if claimAddressBalance.Amount.LT(record.NativeAmount) { + return errorsmod.Wrapf(types.ErrInsufficientFunds, "claim address %s has insufficient funds to confirm sweep unbonded tokens", hostZone.ClaimAddress) + } + + // update record status to CLAIMABLE + record.Status = types.CLAIMABLE + record.UnbondedTokenSweepTxHash = txHash + k.SetUnbondingRecord(ctx, record) + + EmitSuccessfulConfirmUnbondedTokenSweepEvent(ctx, recordId, record.NativeAmount, txHash, sender) + return nil +} + +// Iterates all unbonding records and distributes unbonded tokens to redeemers +// This function will operate atomically by using a cache context wrapper when +// it's invoked. This means that if any redemption send fails across any unbonding +// records, all partial state will be reverted +func (k Keeper) DistributeClaims(ctx sdk.Context) error { + // Get the claim address which will be the sender + // The token denom will be the native host zone token in it's IBC form as it lives on stride + hostZone, err := k.GetUnhaltedHostZone(ctx) + if err != nil { + return err + } + nativeTokenIbcDenom := hostZone.NativeTokenIbcDenom + + claimAddress, err := sdk.AccAddressFromBech32(hostZone.ClaimAddress) + if err != nil { + return errorsmod.Wrapf(err, "invalid host zone claim address %s", hostZone.ClaimAddress) + } + + // Loop through each claimable unbonding record and send out all the relevant claims + for _, unbondingRecord := range k.GetAllUnbondingRecordsByStatus(ctx, types.CLAIMABLE) { + if err := k.DistributeClaimsForUnbondingRecord(ctx, nativeTokenIbcDenom, claimAddress, unbondingRecord.Id); err != nil { + return errorsmod.Wrapf(err, "Unable to distribute claims for unbonding record %d: %s", + unbondingRecord.Id, err.Error()) + } + + // Once all claims have been distributed for a record, archive the record + unbondingRecord.Status = types.CLAIMED + k.ArchiveUnbondingRecord(ctx, unbondingRecord) + } + + return nil +} + +// Distribute claims for a given unbonding record +func (k Keeper) DistributeClaimsForUnbondingRecord( + ctx sdk.Context, + hostNativeIbcDenom string, + claimAddress sdk.AccAddress, + unbondingRecordId uint64, +) error { + k.Logger(ctx).Info(utils.LogWithHostZone(types.DymensionChainId, + "Distributing claims for unbonding record %d", unbondingRecordId)) + + // For each redemption record, bank send from the claim address to the user address and then delete the record + for _, redemptionRecord := range k.GetRedemptionRecordsFromUnbondingId(ctx, unbondingRecordId) { + userAddress, err := sdk.AccAddressFromBech32(redemptionRecord.Redeemer) + if err != nil { + return errorsmod.Wrapf(err, "invalid redeemer address %s", userAddress) + } + + nativeTokens := sdk.NewCoin(hostNativeIbcDenom, redemptionRecord.NativeAmount) + if err := k.bankKeeper.SendCoins(ctx, claimAddress, userAddress, sdk.NewCoins(nativeTokens)); err != nil { + return errorsmod.Wrapf(err, "unable to send %v from claim address to %s", + nativeTokens, redemptionRecord.Redeemer) + } + + k.RemoveRedemptionRecord(ctx, unbondingRecordId, redemptionRecord.Redeemer) + } + return nil +} + +// Runs prepare undelegations with a cache context wrapper so revert any partial state changes +func (k Keeper) SafelyPrepareUndelegation(ctx sdk.Context, epochNumber uint64) error { + return utils.ApplyFuncIfNoError(ctx, func(ctx sdk.Context) error { + return k.PrepareUndelegation(ctx, epochNumber) + }) +} + +// Runs distribute claims with a cache context wrapper so revert any partial state changes +func (k Keeper) SafelyDistributeClaims(ctx sdk.Context) error { + return utils.ApplyFuncIfNoError(ctx, func(ctx sdk.Context) error { + return k.DistributeClaims(ctx) + }) +} diff --git a/x/stakedym/keeper/unbonding_record.go b/x/stakedym/keeper/unbonding_record.go new file mode 100644 index 0000000000..668dec9232 --- /dev/null +++ b/x/stakedym/keeper/unbonding_record.go @@ -0,0 +1,130 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// Writes an unbonding record to the active store +func (k Keeper) SetUnbondingRecord(ctx sdk.Context, unbondingRecord types.UnbondingRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.UnbondingRecordsKeyPrefix) + + recordKey := types.IntKey(unbondingRecord.Id) + recordValue := k.cdc.MustMarshal(&unbondingRecord) + + store.Set(recordKey, recordValue) +} + +// Writes an unbonding record to the archive store +func (k Keeper) SetArchivedUnbondingRecord(ctx sdk.Context, unbondingRecord types.UnbondingRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.UnbondingRecordsArchiveKeyPrefix) + + recordKey := types.IntKey(unbondingRecord.Id) + recordValue := k.cdc.MustMarshal(&unbondingRecord) + + store.Set(recordKey, recordValue) +} + +// Reads a unbonding record from the active store +func (k Keeper) GetUnbondingRecord(ctx sdk.Context, recordId uint64) (unbondingRecord types.UnbondingRecord, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.UnbondingRecordsKeyPrefix) + + recordKey := types.IntKey(recordId) + recordBz := store.Get(recordKey) + + if len(recordBz) == 0 { + return unbondingRecord, false + } + + k.cdc.MustUnmarshal(recordBz, &unbondingRecord) + return unbondingRecord, true +} + +// Reads a unbonding record from the archive store +func (k Keeper) GetArchivedUnbondingRecord(ctx sdk.Context, recordId uint64) (unbondingRecord types.UnbondingRecord, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.UnbondingRecordsArchiveKeyPrefix) + + recordKey := types.IntKey(recordId) + recordBz := store.Get(recordKey) + + if len(recordBz) == 0 { + return unbondingRecord, false + } + + k.cdc.MustUnmarshal(recordBz, &unbondingRecord) + return unbondingRecord, true +} + +// Removes an unbonding record from the active store +func (k Keeper) RemoveUnbondingRecord(ctx sdk.Context, recordId uint64) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.UnbondingRecordsKeyPrefix) + recordKey := types.IntKey(recordId) + store.Delete(recordKey) +} + +// Removes a unbonding record from the active store, and writes it to the archive store +// to preserve history +func (k Keeper) ArchiveUnbondingRecord(ctx sdk.Context, unbondingRecord types.UnbondingRecord) { + k.RemoveUnbondingRecord(ctx, unbondingRecord.Id) + k.SetArchivedUnbondingRecord(ctx, unbondingRecord) +} + +// Returns all active unbonding records +func (k Keeper) GetAllActiveUnbondingRecords(ctx sdk.Context) (unbondingRecords []types.UnbondingRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.UnbondingRecordsKeyPrefix) + return k.getAllUnbondingRecords(store) +} + +// Returns all unbonding records that have been archived +func (k Keeper) GetAllArchivedUnbondingRecords(ctx sdk.Context) (unbondingRecords []types.UnbondingRecord) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.UnbondingRecordsArchiveKeyPrefix) + return k.getAllUnbondingRecords(store) +} + +// Returns all unbonding records for a specified store (either active or archive) +func (k Keeper) getAllUnbondingRecords(store prefix.Store) (unbondingRecords []types.UnbondingRecord) { + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + unbondingRecord := types.UnbondingRecord{} + k.cdc.MustUnmarshal(iterator.Value(), &unbondingRecord) + unbondingRecords = append(unbondingRecords, unbondingRecord) + } + + return unbondingRecords +} + +// Returns all unbonding records with a specific status +// Searches only active records +func (k Keeper) GetAllUnbondingRecordsByStatus(ctx sdk.Context, status types.UnbondingRecordStatus) (unbondingRecords []types.UnbondingRecord) { + for _, unbondingRecord := range k.GetAllActiveUnbondingRecords(ctx) { + if unbondingRecord.Status == status { + unbondingRecords = append(unbondingRecords, unbondingRecord) + } + } + return unbondingRecords +} + +// Gets the ACCUMULATING unbonding record (there should only be one) +func (k Keeper) GetAccumulatingUnbondingRecord(ctx sdk.Context) (unbondingRecord types.UnbondingRecord, err error) { + accumulatingRecord := k.GetAllUnbondingRecordsByStatus(ctx, types.ACCUMULATING_REDEMPTIONS) + if len(accumulatingRecord) == 0 { + return unbondingRecord, types.ErrBrokenUnbondingRecordInvariant.Wrap("no unbonding record in status ACCUMULATING") + } + if len(accumulatingRecord) != 1 { + return unbondingRecord, types.ErrBrokenUnbondingRecordInvariant.Wrap("more than one record in status ACCUMULATING") + } + return accumulatingRecord[0], nil +} + +// Sets the unbonding record only if a record does not already exist for that ID +func (k Keeper) SafelySetUnbondingRecord(ctx sdk.Context, unbondingRecord types.UnbondingRecord) error { + if _, found := k.GetUnbondingRecord(ctx, unbondingRecord.Id); found { + return types.ErrUnbondingRecordAlreadyExists.Wrapf("unbonding record already exists for ID %d", unbondingRecord.Id) + } + k.SetUnbondingRecord(ctx, unbondingRecord) + return nil +} diff --git a/x/stakedym/keeper/unbonding_record_test.go b/x/stakedym/keeper/unbonding_record_test.go new file mode 100644 index 0000000000..11a26b58e2 --- /dev/null +++ b/x/stakedym/keeper/unbonding_record_test.go @@ -0,0 +1,131 @@ +package keeper_test + +import ( + sdkmath "cosmossdk.io/math" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +func (s *KeeperTestSuite) addUnbondingRecords() (unbondingRecords []types.UnbondingRecord) { + for i := 0; i <= 4; i++ { + unbondingRecord := types.UnbondingRecord{ + Id: uint64(i), + NativeAmount: sdkmath.NewInt(int64(i) * 1000), + StTokenAmount: sdkmath.NewInt(int64(i) * 1000), + } + unbondingRecords = append(unbondingRecords, unbondingRecord) + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, unbondingRecord) + } + return unbondingRecords +} + +func (s *KeeperTestSuite) TestGetUnbondingRecord() { + unbondingRecords := s.addUnbondingRecords() + + for i := 0; i < len(unbondingRecords); i++ { + expectedRecord := unbondingRecords[i] + recordId := expectedRecord.Id + + actualRecord, found := s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, recordId) + s.Require().True(found, "unbonding record %d should have been found", i) + s.Require().Equal(expectedRecord, actualRecord) + } +} + +// Tests ArchiveUnbondingRecord and GetAllArchivedUnbondingRecords +func (s *KeeperTestSuite) TestArchiveUnbondingRecord() { + unbondingRecords := s.addUnbondingRecords() + + for removedIndex := 0; removedIndex < len(unbondingRecords); removedIndex++ { + // Archive from removed index + removedRecord := unbondingRecords[removedIndex] + s.App.StakedymKeeper.ArchiveUnbondingRecord(s.Ctx, removedRecord) + + // Confirm removed from the active store + _, found := s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, removedRecord.Id) + s.Require().False(found, "record %d should have been removed", removedRecord.Id) + + // Confirm moved to the archive store + _, found = s.App.StakedymKeeper.GetArchivedUnbondingRecord(s.Ctx, removedRecord.Id) + s.Require().True(found, "record %d should have been moved to the archive store", removedRecord.Id) + + // Check all other records are still there + for checkedIndex := removedIndex + 1; checkedIndex < len(unbondingRecords); checkedIndex++ { + checkedId := unbondingRecords[checkedIndex].Id + _, found := s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, checkedId) + s.Require().True(found, "record %d should have been removed after %d removal", checkedId, removedRecord.Id) + } + } + + // Check that they were all archived + archivedRecords := s.App.StakedymKeeper.GetAllArchivedUnbondingRecords(s.Ctx) + for i := 0; i < len(unbondingRecords); i++ { + expectedRecordId := unbondingRecords[i].Id + s.Require().Equal(expectedRecordId, archivedRecords[i].Id, "archived record %d", i) + } +} + +func (s *KeeperTestSuite) TestGetAllActiveUnbondingRecords() { + expectedRecords := s.addUnbondingRecords() + actualRecords := s.App.StakedymKeeper.GetAllActiveUnbondingRecords(s.Ctx) + s.Require().Equal(len(expectedRecords), len(actualRecords), "number of unbonding records") + s.Require().Equal(expectedRecords, actualRecords) +} + +func (s *KeeperTestSuite) TestGetAccumulatingUnbondingRecord() { + expectedRecordId := uint64(3) + + // Set a few records in the store + unbondingRecords := []types.UnbondingRecord{ + {Id: 1, Status: types.UNBONDING_QUEUE}, + {Id: 2, Status: types.UNBONDING_IN_PROGRESS}, + {Id: 3, Status: types.ACCUMULATING_REDEMPTIONS}, + {Id: 4, Status: types.UNBONDED}, + } + for _, unbondingRecord := range unbondingRecords { + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, unbondingRecord) + } + + // Confirm we find the relevant one + actualAccumulatingRecord, err := s.App.StakedymKeeper.GetAccumulatingUnbondingRecord(s.Ctx) + s.Require().NoError(err, "no error expected when grabbing accumulating record") + s.Require().Equal(expectedRecordId, actualAccumulatingRecord.Id, "found different record than expected") + + // Create an extra ACCUMULATING record and check that it causes an error upon lookup + duplicateAccumulatingRecordId := uint64(5) + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, types.UnbondingRecord{ + Id: duplicateAccumulatingRecordId, + Status: types.ACCUMULATING_REDEMPTIONS, + }) + + _, err = s.App.StakedymKeeper.GetAccumulatingUnbondingRecord(s.Ctx) + s.Require().ErrorContains(err, "more than one record") + + // Remove the ACCUMULATING records and confirm it errors + s.App.StakedymKeeper.RemoveUnbondingRecord(s.Ctx, expectedRecordId) + s.App.StakedymKeeper.RemoveUnbondingRecord(s.Ctx, duplicateAccumulatingRecordId) + + _, err = s.App.StakedymKeeper.GetAccumulatingUnbondingRecord(s.Ctx) + s.Require().ErrorContains(err, "no unbonding record") +} + +func (s *KeeperTestSuite) TestSafelySetUnbondingRecord() { + // Set an unbonding record with ID 1 + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, types.UnbondingRecord{Id: 1}) + + // Try to set another record at ID 1 using SafelySet - it should error + err := s.App.StakedymKeeper.SafelySetUnbondingRecord(s.Ctx, types.UnbondingRecord{Id: 1}) + s.Require().ErrorContains(err, "unbonding record already exists") + + // Set a record at ID 2 - it should succeed + err = s.App.StakedymKeeper.SafelySetUnbondingRecord(s.Ctx, types.UnbondingRecord{Id: 2}) + s.Require().NoError(err, "no error expected when setting new record") + + // Confirm there are two records + unbondingRecords := s.App.StakedymKeeper.GetAllActiveUnbondingRecords(s.Ctx) + s.Require().Len(unbondingRecords, 2, "there should be two unbonding records") + + expectedUnbondingRecordIds := []uint64{1, 2} + actualUnbondingRecordIds := []uint64{unbondingRecords[0].Id, unbondingRecords[1].Id} + s.Require().ElementsMatch(expectedUnbondingRecordIds, actualUnbondingRecordIds, "unbonding record Ids") +} diff --git a/x/stakedym/keeper/unbonding_test.go b/x/stakedym/keeper/unbonding_test.go new file mode 100644 index 0000000000..4065ff11b6 --- /dev/null +++ b/x/stakedym/keeper/unbonding_test.go @@ -0,0 +1,1226 @@ +package keeper_test + +import ( + "time" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/Stride-Labs/stride/v18/app/apptesting" + "github.com/Stride-Labs/stride/v18/utils" + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +const DefaultClaimFundingAmount = 2600 // sum of NativeTokenAmount of records with status UNBONDED + +// ---------------------------------------------- +// RedeemStake +// ---------------------------------------------- + +type Account struct { + account sdk.AccAddress + stTokens sdk.Coin + nativeTokens sdk.Coin +} + +type RedeemStakeTestCase struct { + testName string + + userAccount Account + hostZone *types.HostZone + accUnbondRecord *types.UnbondingRecord + redemptionRecord *types.RedemptionRecord + redeemMsg types.MsgRedeemStake + + expectedUnbondingRecord *types.UnbondingRecord + expectedRedemptionRecord *types.RedemptionRecord + expectedErrorContains string +} + +// Create the correct amounts in accounts, setup the records in store +func (s *KeeperTestSuite) SetupTestRedeemStake( + userAccount Account, + hostZone *types.HostZone, + accUnbondRecord *types.UnbondingRecord, + redemptionRecord *types.RedemptionRecord, +) { + s.FundAccount(userAccount.account, userAccount.nativeTokens) + s.FundAccount(userAccount.account, userAccount.stTokens) + + if hostZone != nil { + s.App.StakedymKeeper.SetHostZone(s.Ctx, *hostZone) + } + + if accUnbondRecord != nil { + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, *accUnbondRecord) + } + + if hostZone != nil && accUnbondRecord != nil && + accUnbondRecord.StTokenAmount.IsPositive() { + escrowAccount, err := sdk.AccAddressFromBech32(hostZone.RedemptionAddress) + if err == nil { + stTokens := sdk.NewInt64Coin(StDenom, accUnbondRecord.StTokenAmount.Int64()) + s.FundAccount(escrowAccount, stTokens) + } + } + + if redemptionRecord != nil { + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, *redemptionRecord) + } +} + +// Default values for key variables, different tests will change 1-2 fields for setup +func (s *KeeperTestSuite) getDefaultTestInputs() ( + *Account, + *types.HostZone, + *types.UnbondingRecord, + *types.RedemptionRecord, + *types.MsgRedeemStake, +) { + redeemerAccount := s.TestAccs[0] + redemptionAccount := s.TestAccs[1] + + defaultUserAccount := Account{ + account: redeemerAccount, + nativeTokens: sdk.NewInt64Coin(HostNativeDenom, 10_000_000), + stTokens: sdk.NewInt64Coin(StDenom, 10_000_000), + } + + redemptionRate := sdk.MustNewDecFromStr("1.1") + defaultHostZone := types.HostZone{ + NativeTokenDenom: HostNativeDenom, + RedemptionAddress: redemptionAccount.String(), + RedemptionRate: redemptionRate, + MinRedemptionRate: redemptionRate.Sub(sdk.MustNewDecFromStr("0.2")), + MinInnerRedemptionRate: redemptionRate.Sub(sdk.MustNewDecFromStr("0.1")), + MaxInnerRedemptionRate: redemptionRate.Add(sdk.MustNewDecFromStr("0.1")), + MaxRedemptionRate: redemptionRate.Add(sdk.MustNewDecFromStr("0.2")), + DelegatedBalance: sdkmath.NewInt(1_000_000_000), + Halted: false, + } + + defaultAccUnbondingRecord := types.UnbondingRecord{ + Id: uint64(105), + Status: types.ACCUMULATING_REDEMPTIONS, + StTokenAmount: sdk.NewInt(700_000), + NativeAmount: sdk.NewInt(770_000), + } + + // RR as it would exist for this default user and UnbondingRecord if had previously + // performed an RedeemStake action this epoch for 400_000 stTokens + defaultRedemptionRecord := types.RedemptionRecord{ + UnbondingRecordId: defaultAccUnbondingRecord.Id, + Redeemer: redeemerAccount.String(), + StTokenAmount: sdk.NewInt(400_000), + NativeAmount: sdk.NewInt(440_000), + } + + defaultMsg := types.MsgRedeemStake{ + Redeemer: redeemerAccount.String(), + StTokenAmount: sdk.NewInt(1_000_000), + } + + return &defaultUserAccount, &defaultHostZone, &defaultAccUnbondingRecord, + &defaultRedemptionRecord, &defaultMsg +} + +func (s *KeeperTestSuite) TestRedeemStake() { + defaultUA, defaultHZ, defaultUR, defaultRR, defaultMsg := s.getDefaultTestInputs() + + testCases := []RedeemStakeTestCase{ + { + testName: "[Error] Can't find the HostZone", + + userAccount: *defaultUA, + hostZone: nil, + + expectedErrorContains: types.ErrHostZoneNotFound.Error(), + }, + { + testName: "[Error] Can't parse redemption address", + + userAccount: *defaultUA, + hostZone: func() *types.HostZone { + _, hz, _, _, _ := s.getDefaultTestInputs() + hz.RedemptionAddress = "nonparsable-address" + return hz + }(), + + expectedErrorContains: "could not bech32 decode redemption address", + }, + { + testName: "[Error] HostZone is halted", + + userAccount: *defaultUA, + hostZone: func() *types.HostZone { + _, hz, _, _, _ := s.getDefaultTestInputs() + hz.Halted = true + return hz + }(), + + expectedErrorContains: types.ErrHostZoneHalted.Error(), + }, + { + testName: "[Error] RedemptionRate outside of bounds", + + userAccount: *defaultUA, + hostZone: func() *types.HostZone { + _, hz, _, _, _ := s.getDefaultTestInputs() + hz.RedemptionRate = sdk.MustNewDecFromStr("5.2") + return hz + }(), + + expectedErrorContains: types.ErrRedemptionRateOutsideSafetyBounds.Error(), + }, + { + testName: "[Error] No Accumulating UndondingRecord", + + userAccount: *defaultUA, + hostZone: defaultHZ, + accUnbondRecord: nil, + + expectedErrorContains: types.ErrBrokenUnbondingRecordInvariant.Error(), + }, + { + testName: "[Error] Not enough tokens in wallet", + + userAccount: func() Account { + acc, _, _, _, _ := s.getDefaultTestInputs() + acc.stTokens.Amount = sdk.NewInt(500_000) + return *acc + }(), + hostZone: defaultHZ, + accUnbondRecord: defaultUR, + redeemMsg: *defaultMsg, // attempt to redeem 1_000_000 stTokens + + expectedErrorContains: sdkerrors.ErrInsufficientFunds.Error(), + }, + { + testName: "[Error] Redeeming more than HostZone delegation total", + + userAccount: func() Account { + acc, _, _, _, _ := s.getDefaultTestInputs() + acc.stTokens.Amount = sdk.NewInt(5_000_000_000) + return *acc + }(), + hostZone: defaultHZ, // 1_000_000_000 total delegation + accUnbondRecord: defaultUR, + redeemMsg: func() types.MsgRedeemStake { + _, _, _, _, msg := s.getDefaultTestInputs() + msg.StTokenAmount = sdk.NewInt(5_000_000_000) + return *msg + }(), + + expectedErrorContains: types.ErrUnbondAmountToLarge.Error(), + }, + { + testName: "[Success] No RR exists yet, RedeemStake tx creates one", + + userAccount: *defaultUA, + hostZone: defaultHZ, + accUnbondRecord: defaultUR, + redemptionRecord: nil, + redeemMsg: *defaultMsg, // redeem 1_000_000 stTokens + + expectedUnbondingRecord: func() *types.UnbondingRecord { + _, hz, ur, _, msg := s.getDefaultTestInputs() + ur.StTokenAmount = ur.StTokenAmount.Add(msg.StTokenAmount) + nativeDiff := sdk.NewDecFromInt(msg.StTokenAmount).Mul(hz.RedemptionRate).RoundInt() + ur.NativeAmount = ur.NativeAmount.Add(nativeDiff) + return ur + }(), + expectedRedemptionRecord: &types.RedemptionRecord{ + UnbondingRecordId: defaultUR.Id, + Redeemer: defaultMsg.Redeemer, + StTokenAmount: defaultMsg.StTokenAmount, + NativeAmount: sdk.NewDecFromInt(defaultMsg.StTokenAmount).Mul(defaultHZ.RedemptionRate).RoundInt(), + }, + }, + { + testName: "[Success] RR exists already for redeemer, RedeemStake tx updates", + + userAccount: *defaultUA, + hostZone: defaultHZ, + accUnbondRecord: defaultUR, + redemptionRecord: defaultRR, // previous redeemption of 400_000 + redeemMsg: *defaultMsg, // redeem 1_000_000 stTokens + + expectedUnbondingRecord: func() *types.UnbondingRecord { + _, hz, ur, _, msg := s.getDefaultTestInputs() + ur.StTokenAmount = ur.StTokenAmount.Add(msg.StTokenAmount) + nativeDiff := sdk.NewDecFromInt(msg.StTokenAmount).Mul(hz.RedemptionRate).RoundInt() + ur.NativeAmount = ur.NativeAmount.Add(nativeDiff) + return ur + }(), + expectedRedemptionRecord: func() *types.RedemptionRecord { + _, hz, _, rr, msg := s.getDefaultTestInputs() + rr.StTokenAmount = rr.StTokenAmount.Add(msg.StTokenAmount) + nativeDiff := sdk.NewDecFromInt(msg.StTokenAmount).Mul(hz.RedemptionRate).RoundInt() + rr.NativeAmount = rr.NativeAmount.Add(nativeDiff) + return rr + }(), + }, + } + + for _, tc := range testCases { + s.Run(tc.testName, func() { + s.checkRedeemStakeTestCase(tc) + }) + } + +} + +func (s *KeeperTestSuite) checkRedeemStakeTestCase(tc RedeemStakeTestCase) { + s.SetupTest() // reset state + s.SetupTestRedeemStake(tc.userAccount, tc.hostZone, tc.accUnbondRecord, tc.redemptionRecord) + + startingStEscrowBalance := sdk.NewInt64Coin(StDenom, 0) + if tc.hostZone != nil { + escrowAccount, err := sdk.AccAddressFromBech32(tc.hostZone.RedemptionAddress) + if err == nil { + startingStEscrowBalance = s.App.BankKeeper.GetBalance(s.Ctx, escrowAccount, StDenom) + } + } + + // Run the RedeemStake, verify expected errors returned or no errors with expected updates to records + _, err := s.App.StakedymKeeper.RedeemStake(s.Ctx, tc.redeemMsg.Redeemer, tc.redeemMsg.StTokenAmount) + if tc.expectedErrorContains == "" { + // Successful Run Test Case + s.Require().NoError(err, "No error expected during redeem stake execution") + + // check expected updates to Accumulating UnbondingRecord + currentAUR, err := s.App.StakedymKeeper.GetAccumulatingUnbondingRecord(s.Ctx) + s.Require().NoError(err, "No error expected when getting UnbondingRecord") + s.Require().Equal(*tc.expectedUnbondingRecord, currentAUR, "Accumulating UnbondingRecord did not match expected") + + // check expected updates to RedemptionRecord for this user and current UnbondingRecord + currentRR, found := s.App.StakedymKeeper.GetRedemptionRecord(s.Ctx, currentAUR.Id, tc.redeemMsg.Redeemer) + s.Require().True(found, "No RedemptionRecord found after RedeemStake expected to have created one") + s.Require().Equal(*tc.expectedRedemptionRecord, currentRR, "RedemptionRecord did not match expected") + + // In test setup the escrow acc was funded with the number of tokens on starting accumulating UnbondingRecord + // Verify that the redemption account now holds the increased escrowed stTokens matching final UnbondingRecord + escrowAccount, err := sdk.AccAddressFromBech32(tc.hostZone.RedemptionAddress) + s.Require().NoError(err, "No error expected when getting escrow account for successful test") + currentStEscrowBalance := s.App.BankKeeper.GetBalance(s.Ctx, escrowAccount, StDenom) + s.Require().NotEqual(startingStEscrowBalance, currentStEscrowBalance, "Escrowed balance should have changed") + s.Require().Equal(currentStEscrowBalance.Amount, currentAUR.StTokenAmount, "Escrowed balance does not match the UnbondingRecord") + } else { + // Expected Error Test Case + s.Require().Error(err, "Error expected to be returned but none found") + s.Require().ErrorContains(err, tc.expectedErrorContains, "Error did not contain expected message") + } +} + +// ---------------------------------------------- +// PrepareUndelegation +// ---------------------------------------------- + +func (s *KeeperTestSuite) TestPrepareUndelegation() { + accumulatingUnbondingRecordId := uint64(4) + epochNumber := uint64(5) + + // Create the accumulating unbonding record + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, types.UnbondingRecord{ + Id: accumulatingUnbondingRecordId, + Status: types.ACCUMULATING_REDEMPTIONS, + }) + + // Set a host zone with a 1.999 redemption rate + // (an uneven number is used to test rounding/truncation) + oldRedemptionRate := sdk.MustNewDecFromStr("1.9") + redemptionRate := sdk.MustNewDecFromStr("1.999") + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + RedemptionRate: redemptionRate, + }) + + // Define the expected redemption records after the function is called + expectedRedemptionRecords := []types.RedemptionRecord{ + // StTokenAmount: 1000 * 1.999 = 1999 Native + {UnbondingRecordId: 4, Redeemer: "A", StTokenAmount: sdkmath.NewInt(1000), NativeAmount: sdkmath.NewInt(1999)}, + // StTokenAmount: 999 * 1.999 = 1997.001, Rounded down to 1997 Native + {UnbondingRecordId: 4, Redeemer: "B", StTokenAmount: sdkmath.NewInt(999), NativeAmount: sdkmath.NewInt(1997)}, + // StTokenAmount: 100 * 1.999 = 199.9, Rounded up to 200 Native + {UnbondingRecordId: 4, Redeemer: "C", StTokenAmount: sdkmath.NewInt(100), NativeAmount: sdkmath.NewInt(200)}, + + // Different unbonding records, should be excluded + {UnbondingRecordId: 1, Redeemer: "D", StTokenAmount: sdkmath.NewInt(100), NativeAmount: sdkmath.NewInt(100)}, + {UnbondingRecordId: 2, Redeemer: "E", StTokenAmount: sdkmath.NewInt(200), NativeAmount: sdkmath.NewInt(200)}, + {UnbondingRecordId: 3, Redeemer: "F", StTokenAmount: sdkmath.NewInt(300), NativeAmount: sdkmath.NewInt(300)}, + } + expectedTotalNativeAmount := sdkmath.NewInt(1999 + 1997 + 200) + + // Create the initial records, setting the native amount to be slightly less than expected + for _, expectedUserRedemptionRecord := range expectedRedemptionRecords { + initialRedemptionRecord := expectedUserRedemptionRecord + initialRedemptionRecord.NativeAmount = sdk.NewDecFromInt(initialRedemptionRecord.StTokenAmount).Mul(oldRedemptionRate).RoundInt() + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, initialRedemptionRecord) + } + + // Call prepare undelegation + err := s.App.StakedymKeeper.PrepareUndelegation(s.Ctx, epochNumber) + s.Require().NoError(err, "no error expected when calling prepare undelegation") + + // Confirm the total and status was updated on the unbonding record + unbondingRecord, found := s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, accumulatingUnbondingRecordId) + s.Require().True(found) + s.Require().Equal(unbondingRecord.Status, types.UNBONDING_QUEUE, "unbonding record status should have updated") + s.Require().Equal(expectedTotalNativeAmount.Int64(), unbondingRecord.NativeAmount.Int64(), + "total native tokens on unbonding record") + + // Confirm the summation is correct and the redemption records were updated + for _, expectedRecord := range expectedRedemptionRecords { + if expectedRecord.UnbondingRecordId != accumulatingUnbondingRecordId { + continue + } + + unbondingRecordId := expectedRecord.UnbondingRecordId + redeemer := expectedRecord.Redeemer + actualRecord, found := s.App.StakedymKeeper.GetRedemptionRecord(s.Ctx, unbondingRecordId, redeemer) + s.Require().True(found, "record %d %s should have been found", unbondingRecordId, redeemer) + s.Require().Equal(expectedRecord.NativeAmount.Int64(), actualRecord.NativeAmount.Int64(), + "record %s %d native amount", unbondingRecordId, redeemer) + } + + // Confirm a new record was created + newUnbondingRecord, found := s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, epochNumber) + s.Require().True(found, "new unbonding record should have been created") + s.Require().Equal(newUnbondingRecord.Status, types.ACCUMULATING_REDEMPTIONS, "new unbonding record status") + + // Call prepare undelegation again with the new unbonding record + // Since there are no new unbondings, the record should get archived immediately + err = s.App.StakedymKeeper.PrepareUndelegation(s.Ctx, epochNumber+1) + s.Require().NoError(err, "no error expected during second undelegation") + + archivedRecords := s.App.StakedymKeeper.GetAllArchivedUnbondingRecords(s.Ctx) + s.Require().Len(archivedRecords, 1, "record should have been archived") + s.Require().Equal(epochNumber, archivedRecords[0].Id, "archived record ID") + + // Create an unbonding record in non-ACCUMULATING Status + duplicateRecordId := uint64(10) + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, types.UnbondingRecord{ + Id: duplicateRecordId, + Status: types.UNBONDING_QUEUE, + }) + + // Check that if we tried to run prepare with that ID, it would error because the record already exists + err = s.App.StakedymKeeper.PrepareUndelegation(s.Ctx, duplicateRecordId) + s.Require().ErrorContains(err, "unbonding record already exists") + + // Create another accumulating record and check that this would break an invariant and error + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, types.UnbondingRecord{ + Id: 99, + Status: types.ACCUMULATING_REDEMPTIONS, + }) + + err = s.App.StakedymKeeper.PrepareUndelegation(s.Ctx, epochNumber+10) // any epoch in future + s.Require().ErrorContains(err, "more than one record in status ACCUMULATING") + + // Halt the host zone and try again - it should fail + hostZone := s.MustGetHostZone() + hostZone.Halted = true + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + err = s.App.StakedymKeeper.PrepareUndelegation(s.Ctx, epochNumber) + s.Require().ErrorContains(err, "host zone is halted") +} + +// ---------------------------------------------- +// ConfirmUndelegation +// ---------------------------------------------- + +type ConfirmUndelegationTestCase struct { + operatorAddress string + redemptionAddress sdk.AccAddress + stTokenAmountToBurn sdkmath.Int + unbondingRecord types.UnbondingRecord + amountToUndelegate sdkmath.Int + delegatedBalance sdkmath.Int + redemptionAccountBalance sdkmath.Int + hostZone types.HostZone + expectedUnbondingTime uint64 +} + +// Helper function to mock relevant state before testing a confirm undelegation +func (s *KeeperTestSuite) SetupTestConfirmUndelegation(amountToUndelegate sdkmath.Int) ConfirmUndelegationTestCase { + redemptionAddress := s.TestAccs[0] + operatorAddress := s.TestAccs[1] + + redemptionAccountBalance := sdkmath.NewInt(500) + delegatedBalance := sdkmath.NewInt(1000) + unbondingPeriodSeconds := uint64(120) // 2 minutes + expectedUnbondingTime := uint64(s.Ctx.BlockTime().Add(time.Minute * 2).Unix()) + + // Create a host zone with delegatedBalance and RedemptionAddresses + hostZone := types.HostZone{ + DelegatedBalance: delegatedBalance, + RedemptionAddress: redemptionAddress.String(), + NativeTokenDenom: HostNativeDenom, + UnbondingPeriodSeconds: unbondingPeriodSeconds, + MinRedemptionRate: sdk.MustNewDecFromStr("0.9"), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2"), + RedemptionRate: sdk.MustNewDecFromStr("1.1"), + } + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + // Fund the redemption account with tokens that will be burned + stTokensInRedemption := sdk.NewCoin(StDenom, redemptionAccountBalance) + s.FundAccount(redemptionAddress, stTokensInRedemption) + + // create an unbonding record in status UNBONDING_QUEUE + // - stToken amount to burn as if the RR is 1.1 + stTokenAmountToBurn := sdk.NewDecFromInt(amountToUndelegate).Mul(hostZone.RedemptionRate).TruncateInt() + unbondingRecord := types.UnbondingRecord{ + Id: 1, + Status: types.UNBONDING_QUEUE, + StTokenAmount: stTokenAmountToBurn, + NativeAmount: amountToUndelegate, + } + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, unbondingRecord) + + tc := ConfirmUndelegationTestCase{ + redemptionAddress: redemptionAddress, + operatorAddress: operatorAddress.String(), + stTokenAmountToBurn: stTokenAmountToBurn, + unbondingRecord: unbondingRecord, + amountToUndelegate: amountToUndelegate, + delegatedBalance: delegatedBalance, + redemptionAccountBalance: redemptionAccountBalance, + hostZone: hostZone, + expectedUnbondingTime: expectedUnbondingTime, + } + return tc +} + +func (s *KeeperTestSuite) TestConfirmUndelegation_Success() { + amountToUndelegate := sdkmath.NewInt(100) + tc := s.SetupTestConfirmUndelegation(amountToUndelegate) + + // we're halting the zone to test that the tx works even when the host zone is halted + s.App.StakedymKeeper.HaltZone(s.Ctx) + + // confirm the tx was successful + err := s.App.StakedymKeeper.ConfirmUndelegation(s.Ctx, tc.unbondingRecord.Id, ValidTxHashDefault, tc.operatorAddress) + s.Require().NoError(err) + + // check that the unbonding record was updated + unbondingRecord, found := s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, tc.unbondingRecord.Id) + s.Require().True(found, "unbonding record should have been found") + s.Require().Equal(types.UNBONDING_IN_PROGRESS, unbondingRecord.Status, "unbonding record status") + s.Require().Equal(ValidTxHashDefault, unbondingRecord.UndelegationTxHash, "unbonding record tx hash") + s.Require().Equal(tc.expectedUnbondingTime, unbondingRecord.UnbondingCompletionTimeSeconds, "unbonding record completion time") + + // check that the balance on the redemption account was updated + expectedRedemptionAccountBalance := tc.redemptionAccountBalance.Sub(tc.stTokenAmountToBurn) + actualRedemptionAccountBalance := s.App.BankKeeper.GetBalance(s.Ctx, tc.redemptionAddress, StDenom).Amount + s.Require().Equal(expectedRedemptionAccountBalance, actualRedemptionAccountBalance, "redemption account balance") + + // check that delegated balance was updated + hostZone := s.MustGetHostZone() + s.Require().Equal(tc.delegatedBalance.Sub(tc.amountToUndelegate), hostZone.DelegatedBalance, "delegated balance") +} + +// unit test ConfirmUndelegation with nothing to unbond +func (s *KeeperTestSuite) TestConfirmUndelegation_Failure_NothingToUnbond() { + // test undelegating nothing + amountToUndelegate := sdkmath.ZeroInt() + tc := s.SetupTestConfirmUndelegation(amountToUndelegate) + + // require both stTokenAmountToBurn and amountToUndelegate are 0 + s.Require().Zero(tc.stTokenAmountToBurn.Int64()) + s.Require().Zero(tc.amountToUndelegate.Int64()) + + txHash := "" // hash must be empty for nothing to unbond case + err := s.App.StakedymKeeper.ConfirmUndelegation(s.Ctx, tc.unbondingRecord.Id, txHash, tc.operatorAddress) + s.Require().Error(err, "no tokens to unbond") +} + +// unit test ConfirmUndelegation with nothing to unbond +func (s *KeeperTestSuite) TestConfirmUndelegation_Failure_NegativeAmountToUnbond() { + // test undelegating nothing + amountToUndelegateNegative := sdkmath.ZeroInt().Sub(sdkmath.NewInt(1)) + tc := s.SetupTestConfirmUndelegation(amountToUndelegateNegative) + + // require both stTokenAmountToBurn and amountToUndelegate are -1 + s.Require().Negative(tc.stTokenAmountToBurn.Int64()) + s.Require().Negative(tc.amountToUndelegate.Int64()) + + txHash := "" // hash must be empty for nothing to unbond case + err := s.App.StakedymKeeper.ConfirmUndelegation(s.Ctx, tc.unbondingRecord.Id, txHash, tc.operatorAddress) + s.Require().Error(err, "no tokens to unbond (or negative)") +} + +func (s *KeeperTestSuite) TestConfirmUndelegation_Failure_RecordWasNotQueued() { + amountToUndelegate := sdkmath.NewInt(100) + tc := s.SetupTestConfirmUndelegation(amountToUndelegate) + + // set the unbonding record status to something other than UNBONDING_QUEUE + tc.unbondingRecord.Status = types.UNBONDING_IN_PROGRESS + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, tc.unbondingRecord) + + err := s.App.StakedymKeeper.ConfirmUndelegation(s.Ctx, tc.unbondingRecord.Id, ValidTxHashDefault, tc.operatorAddress) + s.Require().Error(err, "not ready to be undelegated") +} + +func (s *KeeperTestSuite) TestConfirmUndelegation_Failure_NoRecordWithId() { + amountToUndelegate := sdkmath.NewInt(100) + tc := s.SetupTestConfirmUndelegation(amountToUndelegate) + + // archive the record (this is the only way to remove it from the active store) + tc.unbondingRecord.Status = types.UNBONDING_IN_PROGRESS + s.App.StakedymKeeper.ArchiveUnbondingRecord(s.Ctx, tc.unbondingRecord) + + err := s.App.StakedymKeeper.ConfirmUndelegation(s.Ctx, tc.unbondingRecord.Id, ValidTxHashDefault, tc.operatorAddress) + s.Require().Error(err, "couldn't find unbonding record") +} + +func (s *KeeperTestSuite) TestConfirmUndelegation_Failure_RecordHashAlreadySet() { + amountToUndelegate := sdkmath.NewInt(100) + tc := s.SetupTestConfirmUndelegation(amountToUndelegate) + + // set the unbonding record tx hash + tc.unbondingRecord.UndelegationTxHash = ValidTxHashDefault + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, tc.unbondingRecord) + + err := s.App.StakedymKeeper.ConfirmUndelegation(s.Ctx, tc.unbondingRecord.Id, ValidTxHashDefault, tc.operatorAddress) + s.Require().Error(err, "already has a tx hash set") +} + +func (s *KeeperTestSuite) TestBurnRedeemedStTokens_Success() { + + redemptionAddress := s.TestAccs[0] + redemptionAccountBalance := sdkmath.NewInt(500) + + // Create a host zone with delegatedBalance and RedemptionAddresses + hostZone := types.HostZone{ + RedemptionAddress: redemptionAddress.String(), + NativeTokenDenom: HostNativeDenom, + } + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + // Fund the redemption account with tokens that will be burned + stTokensInRedemption := sdk.NewCoin(StDenom, redemptionAccountBalance) + s.FundAccount(redemptionAddress, stTokensInRedemption) + + // Store down the stToken supply for checking against after burn + stTokenSupplyBefore := s.App.BankKeeper.GetSupply(s.Ctx, StDenom).Amount + + stDenom := utils.StAssetDenomFromHostZoneDenom(hostZone.NativeTokenDenom) + + // burn redeemed stTokens + tokensToBurn := sdk.NewCoin(stDenom, sdkmath.NewInt(100)) + err := s.App.StakedymKeeper.BurnRedeemedStTokens(s.Ctx, sdk.NewCoins(tokensToBurn), redemptionAddress.String()) + s.Require().NoError(err) + + // check that stDYM supply decremented + stTokenSupplyAfter := s.App.BankKeeper.GetSupply(s.Ctx, StDenom).Amount + s.Require().Equal(stTokenSupplyBefore.Sub(tokensToBurn.Amount), stTokenSupplyAfter, "stToken supply") + + // check that the balance on the redemption account was updated + expectedRedemptionAccountBalance := redemptionAccountBalance.Sub(tokensToBurn.Amount) + actualRedemptionAccountBalance := s.App.BankKeeper.GetBalance(s.Ctx, redemptionAddress, StDenom).Amount + s.Require().Equal(expectedRedemptionAccountBalance, actualRedemptionAccountBalance, "redemption account balance") +} + +func (s *KeeperTestSuite) TestBurnRedeemedStTokens_BadRedemptionAddress() { + + redemptionAddress := "INVALID_ADDRESS" + + // Create a host zone with delegatedBalance and RedemptionAddresses + hostZone := types.HostZone{ + RedemptionAddress: redemptionAddress, + NativeTokenDenom: HostNativeDenom, + } + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + stDenom := utils.StAssetDenomFromHostZoneDenom(hostZone.NativeTokenDenom) + + // burn redeemed stTokens + tokensToBurn := sdk.NewCoin(stDenom, sdkmath.NewInt(100)) + err := s.App.StakedymKeeper.BurnRedeemedStTokens(s.Ctx, sdk.NewCoins(tokensToBurn), redemptionAddress) + s.Require().Error(err, "could not bech32 decode addres") +} + +func (s *KeeperTestSuite) TestVerifyImpliedRedemptionRateFromUnbonding() { + minRRBound := sdk.MustNewDecFromStr("0.9") + maxRRBound := sdk.MustNewDecFromStr("1.1") + + testCases := []struct { + name string + delegatedBalanceBefore sdkmath.Int + delegatedBalanceAfter sdkmath.Int + stTokenSupplyBefore sdkmath.Int + stTokenSupplyAfter sdkmath.Int + expectedError string + }{ + { + // Undelegated: 1000, Burned: 1000, Implied Rate: 1.0 + name: "valid implied rate - 1", + delegatedBalanceBefore: sdkmath.NewInt(5000), + delegatedBalanceAfter: sdkmath.NewInt(4000), // 5000 - 4000 = 1000 undelegated + stTokenSupplyBefore: sdkmath.NewInt(5000), + stTokenSupplyAfter: sdkmath.NewInt(4000), // 5000 - 4000 = 1000 burned + }, + { + // Undelegated: 950, Burned: 1000, Implied Rate: 0.95 + name: "valid implied rate below 1", + delegatedBalanceBefore: sdkmath.NewInt(5000), + delegatedBalanceAfter: sdkmath.NewInt(4050), // 5000 - 4050 = 950 undelegated + stTokenSupplyBefore: sdkmath.NewInt(5000), + stTokenSupplyAfter: sdkmath.NewInt(4000), // 5000 - 4000 = 1000 burned + }, + { + // Undelegated: 1050, Burned: 1000, Implied Rate: 1.05 + name: "valid implied rate above 1", + delegatedBalanceBefore: sdkmath.NewInt(5000), + delegatedBalanceAfter: sdkmath.NewInt(3950), // 5000 - 3950 = 1050 undelegated + stTokenSupplyBefore: sdkmath.NewInt(5000), + stTokenSupplyAfter: sdkmath.NewInt(4000), // 5000 - 4000 = 1000 burned + }, + { + // Undelegated: 900, Burned: 1000, Implied Rate: 0.9 + name: "valid implied rate at min", + delegatedBalanceBefore: sdkmath.NewInt(5000), + delegatedBalanceAfter: sdkmath.NewInt(4000), // 5000 - 4000 = 900 undelegated + stTokenSupplyBefore: sdkmath.NewInt(5000), + stTokenSupplyAfter: sdkmath.NewInt(4000), // 5000 - 4000 = 1000 burned + }, + { + // Undelegated: 1100, Burned: 1000, Implied Rate: 1.1 + name: "valid implied rate at max", + delegatedBalanceBefore: sdkmath.NewInt(5000), + delegatedBalanceAfter: sdkmath.NewInt(3900), // 5000 - 3900 = 1100 undelegated + stTokenSupplyBefore: sdkmath.NewInt(5000), + stTokenSupplyAfter: sdkmath.NewInt(4000), // 5000 - 4000 = 1000 burned + }, + { + // Undelegated: 899, Burned: 1000, Implied Rate: 0.899 + name: "valid implied rate below min", + delegatedBalanceBefore: sdkmath.NewInt(5000), + delegatedBalanceAfter: sdkmath.NewInt(4101), // 5000 - 4101 = 899 undelegated + stTokenSupplyBefore: sdkmath.NewInt(5000), + stTokenSupplyAfter: sdkmath.NewInt(4000), // 5000 - 4000 = 1000 burned + expectedError: "redemption rate outside safety bounds", + }, + { + // Undelegated: 1101, Burned: 1000, Implied Rate: 1.101 + name: "valid implied rate above max", + delegatedBalanceBefore: sdkmath.NewInt(5000), + delegatedBalanceAfter: sdkmath.NewInt(3899), // 5000 - 3899 = 1101 undelegated + stTokenSupplyBefore: sdkmath.NewInt(5000), + stTokenSupplyAfter: sdkmath.NewInt(4000), // 5000 - 4000 = 1000 burned + expectedError: "redemption rate outside safety bounds", + }, + { + name: "division by zero", + delegatedBalanceBefore: sdkmath.NewInt(1000), + delegatedBalanceAfter: sdkmath.NewInt(2000), + stTokenSupplyBefore: sdkmath.NewInt(4000), + stTokenSupplyAfter: sdkmath.NewInt(4000), // same as before -> supply change is 0 + expectedError: "division by zero", + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.SetupTest() // reset state + + // Mint stTokens to a random account to create supply + s.FundAccount(s.TestAccs[0], sdk.NewCoin(StDenom, tc.stTokenSupplyAfter)) + + // Set the delegated balance on the host zone + s.App.StakedymKeeper.SetHostZone(s.Ctx, types.HostZone{ + NativeTokenDenom: HostNativeDenom, + DelegatedBalance: tc.delegatedBalanceAfter, + MinRedemptionRate: minRRBound, + MaxRedemptionRate: maxRRBound, + }) + + // verify that the implied redemption rate is between the bounds + err := s.App.StakedymKeeper.VerifyImpliedRedemptionRateFromUnbonding(s.Ctx, tc.stTokenSupplyBefore, tc.delegatedBalanceBefore) + + if tc.expectedError == "" { + s.Require().NoError(err) + } else { + s.Require().ErrorContains(err, tc.expectedError) + } + }) + } +} + +// ---------------------------------------------- +// ConfirmUnbondedTokensSwept +// ---------------------------------------------- + +func (s *KeeperTestSuite) GetDefaultUnbondingRecords() []types.UnbondingRecord { + unbondingRecords := []types.UnbondingRecord{ // verify no issue if these are out of order + { + Id: 1, + Status: types.UNBONDING_QUEUE, + StTokenAmount: sdk.NewInt(100), + NativeAmount: sdk.NewInt(200), + UnbondingCompletionTimeSeconds: 0, + UndelegationTxHash: "", + UnbondedTokenSweepTxHash: "", + }, + { + Id: 7, + Status: types.CLAIMABLE, + StTokenAmount: sdk.NewInt(200), + NativeAmount: sdk.NewInt(400), + UnbondingCompletionTimeSeconds: 10, + UndelegationTxHash: ValidTxHashDefault, + UnbondedTokenSweepTxHash: ValidTxHashDefault, + }, + { + Id: 5, + Status: types.UNBONDING_IN_PROGRESS, + StTokenAmount: sdk.NewInt(500), + NativeAmount: sdk.NewInt(1000), + UnbondingCompletionTimeSeconds: 20, + UndelegationTxHash: ValidTxHashDefault, + UnbondedTokenSweepTxHash: "", + }, + { + Id: 3, + Status: types.ACCUMULATING_REDEMPTIONS, + StTokenAmount: sdk.NewInt(300), + NativeAmount: sdk.NewInt(600), + UnbondingCompletionTimeSeconds: 0, + UndelegationTxHash: "", + UnbondedTokenSweepTxHash: "", + }, + { + Id: 6, + Status: types.UNBONDED, + StTokenAmount: sdk.NewInt(600), + NativeAmount: sdk.NewInt(1200), + UnbondingCompletionTimeSeconds: 15, + UndelegationTxHash: ValidTxHashDefault, + UnbondedTokenSweepTxHash: "", + }, + { + Id: 4, + Status: types.CLAIMABLE, + StTokenAmount: sdk.NewInt(400), + NativeAmount: sdk.NewInt(800), + UnbondingCompletionTimeSeconds: 5, + UndelegationTxHash: ValidTxHashDefault, + UnbondedTokenSweepTxHash: ValidTxHashDefault, + }, + { + Id: 2, + Status: types.UNBONDED, + StTokenAmount: sdk.NewInt(700), + NativeAmount: sdk.NewInt(1400), + UnbondingCompletionTimeSeconds: 18, + UndelegationTxHash: ValidTxHashDefault, + UnbondedTokenSweepTxHash: "", + }, + } + return unbondingRecords +} + +// Helper function to setup unbonding records, returns a list of records +func (s *KeeperTestSuite) SetupTestConfirmUnbondingTokens(amount int64) { + unbondingRecords := s.GetDefaultUnbondingRecords() + + // loop through and set each record + for _, unbondingRecord := range unbondingRecords { + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, unbondingRecord) + } + + // setup host zone, to fund claim address + claimAddress := s.TestAccs[0] + hostZone := types.HostZone{ + NativeTokenIbcDenom: HostIBCDenom, + ClaimAddress: claimAddress.String(), + } + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + // fund claim address + liquidStakeToken := sdk.NewCoin(hostZone.NativeTokenIbcDenom, sdk.NewInt(amount)) + s.FundAccount(claimAddress, liquidStakeToken) +} + +func (s *KeeperTestSuite) VerifyUnbondingRecordsAfterConfirmSweep(verifyUpdatedFieldsIdentical bool) { + defaultUnbondingRecords := s.GetDefaultUnbondingRecords() + for _, defaultUnbondingRecord := range defaultUnbondingRecords { + // grab relevant record in store + loadedUnbondingRecord, found := s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, defaultUnbondingRecord.Id) + s.Require().True(found) + + // verify record is correct + s.Require().Equal(defaultUnbondingRecord.Id, loadedUnbondingRecord.Id) + s.Require().Equal(defaultUnbondingRecord.NativeAmount, loadedUnbondingRecord.NativeAmount) + s.Require().Equal(defaultUnbondingRecord.StTokenAmount, loadedUnbondingRecord.StTokenAmount) + s.Require().Equal(defaultUnbondingRecord.UnbondingCompletionTimeSeconds, loadedUnbondingRecord.UnbondingCompletionTimeSeconds) + s.Require().Equal(defaultUnbondingRecord.UndelegationTxHash, loadedUnbondingRecord.UndelegationTxHash) + + // if relevant, verify status and tx hash + if (defaultUnbondingRecord.Status != types.UNBONDED) || + verifyUpdatedFieldsIdentical { + s.Require().Equal(defaultUnbondingRecord.Status, loadedUnbondingRecord.Status) + s.Require().Equal(defaultUnbondingRecord.UnbondedTokenSweepTxHash, loadedUnbondingRecord.UnbondedTokenSweepTxHash) + } + } +} + +func (s *KeeperTestSuite) TestConfirmUnbondingTokenSweep_Successful() { + s.SetupTestConfirmUnbondingTokens(DefaultClaimFundingAmount) + + // we're halting the zone to test that the tx works even when the host zone is halted + s.App.StakedymKeeper.HaltZone(s.Ctx) + + // process record 6 + err := s.App.StakedymKeeper.ConfirmUnbondedTokenSweep(s.Ctx, 6, ValidTxHashNew, ValidOperator) + s.Require().NoError(err) + s.VerifyUnbondingRecordsAfterConfirmSweep(false) + + // verify record 6 modified + loadedUnbondingRecord, found := s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, 6) + s.Require().True(found) + s.Require().Equal(types.CLAIMABLE, loadedUnbondingRecord.Status, "unbonding record should be updated to status CLAIMABLE") + s.Require().Equal(ValidTxHashNew, loadedUnbondingRecord.UnbondedTokenSweepTxHash, "unbonding record should be updated with token sweep txHash") + + // process record 2 + err = s.App.StakedymKeeper.ConfirmUnbondedTokenSweep(s.Ctx, 2, ValidTxHashNew, ValidOperator) + s.Require().NoError(err) + s.VerifyUnbondingRecordsAfterConfirmSweep(false) + + // verify record 2 modified + loadedUnbondingRecord, found = s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, 2) + s.Require().True(found) + s.Require().Equal(types.CLAIMABLE, loadedUnbondingRecord.Status, "unbonding record should be updated to status CLAIMABLE") + s.Require().Equal(ValidTxHashNew, loadedUnbondingRecord.UnbondedTokenSweepTxHash, "unbonding record should be updated with token sweep txHash") + +} + +func (s *KeeperTestSuite) TestConfirmUnbondingTokenSweep_NotFunded() { + s.SetupTestConfirmUnbondingTokens(10) + + // try setting with no hash + err := s.App.StakedymKeeper.ConfirmUnbondedTokenSweep(s.Ctx, 6, ValidTxHashNew, ValidOperator) + s.Require().ErrorIs(err, types.ErrInsufficientFunds, "should error when claim account doesn't have enough funds") +} + +func (s *KeeperTestSuite) TestConfirmUnbondingTokenSweep_InvalidClaimAddress() { + s.SetupTestConfirmUnbondingTokens(DefaultClaimFundingAmount) + + hostZone := s.MustGetHostZone() + hostZone.ClaimAddress = "strideinvalidaddress" // random address + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + // try setting with no hash + err := s.App.StakedymKeeper.ConfirmUnbondedTokenSweep(s.Ctx, 6, ValidTxHashNew, ValidOperator) + s.Require().ErrorContains(err, "decoding bech32 failed", "should error when claim address is invalid") +} + +func (s *KeeperTestSuite) TestConfirmUnbondingTokenSweep_RecordDoesntExist() { + s.SetupTestConfirmUnbondingTokens(DefaultClaimFundingAmount) + + // process record 15 + err := s.App.StakedymKeeper.ConfirmUnbondedTokenSweep(s.Ctx, 15, ValidTxHashNew, ValidOperator) + s.Require().ErrorIs(err, types.ErrUnbondingRecordNotFound, "should error when record doesn't exist") +} + +func (s *KeeperTestSuite) TestConfirmUnbondingTokenSweep_RecordIncorrectState() { + s.SetupTestConfirmUnbondingTokens(DefaultClaimFundingAmount) + + // get list of ids to try + ids := []uint64{1, 3, 5, 7} + for _, id := range ids { + err := s.App.StakedymKeeper.ConfirmUnbondedTokenSweep(s.Ctx, id, ValidTxHashNew, ValidOperator) + s.Require().ErrorIs(err, types.ErrInvalidUnbondingRecord, "should error when record is in incorrect state") + } +} + +func (s *KeeperTestSuite) TestConfirmUnbondingTokenSweep_ZeroSweepAmount() { + s.SetupTestConfirmUnbondingTokens(DefaultClaimFundingAmount) + + // update the sweep record so that the native amount is zero + unbondingRecord, found := s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, 6) + s.Require().True(found) + unbondingRecord.NativeAmount = sdk.NewInt(0) + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, unbondingRecord) + + // try confirming with zero token amount on record + err := s.App.StakedymKeeper.ConfirmUnbondedTokenSweep(s.Ctx, 6, ValidTxHashNew, ValidOperator) + s.Require().ErrorIs(err, types.ErrInvalidUnbondingRecord, "should error when record has zero sweep amount") +} + +func (s *KeeperTestSuite) TestConfirmUnbondingTokenSweep_NegativeSweepAmount() { + s.SetupTestConfirmUnbondingTokens(DefaultClaimFundingAmount) + + // update the sweep record so that the native amount is negative + unbondingRecord, found := s.App.StakedymKeeper.GetUnbondingRecord(s.Ctx, 6) + s.Require().True(found) + unbondingRecord.StTokenAmount = sdk.NewInt(-10) + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, unbondingRecord) + + // try confirming with negative token amount on record + err := s.App.StakedymKeeper.ConfirmUnbondedTokenSweep(s.Ctx, 6, ValidTxHashNew, ValidOperator) + s.Require().ErrorIs(err, types.ErrInvalidUnbondingRecord, "should error when record has zero sweep amount") +} + +// ---------------------------------------------- +// DistributeClaims +// ---------------------------------------------- + +type DistributeClaimsTestCase struct { + claimAddress sdk.AccAddress + claimableRecordIds []uint64 + expectedFinalClaimBalance sdkmath.Int +} + +func (s *KeeperTestSuite) TestMarkFinishedUnbondings() { + currentTime := uint64(s.Ctx.BlockTime().Unix()) + + // Set unbonding records across different statuses and times + finishedUnbondingIds := map[uint64]bool{7: true, 8: true, 9: true} + initialUnbondingRecords := []types.UnbondingRecord{ + {Id: 1, Status: types.ACCUMULATING_REDEMPTIONS, UnbondingCompletionTimeSeconds: currentTime - 1}, + {Id: 2, Status: types.ACCUMULATING_REDEMPTIONS, UnbondingCompletionTimeSeconds: currentTime}, + {Id: 3, Status: types.ACCUMULATING_REDEMPTIONS, UnbondingCompletionTimeSeconds: currentTime + 1}, + + {Id: 4, Status: types.UNBONDING_QUEUE, UnbondingCompletionTimeSeconds: currentTime - 1}, + {Id: 5, Status: types.UNBONDING_QUEUE, UnbondingCompletionTimeSeconds: currentTime}, + {Id: 6, Status: types.UNBONDING_QUEUE, UnbondingCompletionTimeSeconds: currentTime + 1}, + + {Id: 7, Status: types.UNBONDING_IN_PROGRESS, UnbondingCompletionTimeSeconds: currentTime - 3}, // finished + {Id: 8, Status: types.UNBONDING_IN_PROGRESS, UnbondingCompletionTimeSeconds: currentTime - 2}, // finished + {Id: 9, Status: types.UNBONDING_IN_PROGRESS, UnbondingCompletionTimeSeconds: currentTime - 1}, // finished + + {Id: 10, Status: types.UNBONDING_IN_PROGRESS, UnbondingCompletionTimeSeconds: currentTime}, // still unbonding + {Id: 11, Status: types.UNBONDING_IN_PROGRESS, UnbondingCompletionTimeSeconds: currentTime + 1}, // still unbonding + + {Id: 12, Status: types.UNBONDED, UnbondingCompletionTimeSeconds: currentTime + 1}, + } + for _, unbondingRecord := range initialUnbondingRecords { + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, unbondingRecord) + } + + // Call check unbonding finished + s.App.StakedymKeeper.MarkFinishedUnbondings(s.Ctx) + + // Check that the relevant records were updated + for i, actualUnbondingRecord := range s.App.StakedymKeeper.GetAllActiveUnbondingRecords(s.Ctx) { + if _, ok := finishedUnbondingIds[actualUnbondingRecord.Id]; ok { + s.Require().Equal(actualUnbondingRecord.Status, types.UNBONDED, + "record %d should have been marked as unbonded", actualUnbondingRecord.Id) + } else { + initialRecord := initialUnbondingRecords[i] + s.Require().Equal(initialRecord.Status, actualUnbondingRecord.Status, + "record %d status should not have changed", actualUnbondingRecord.Id) + } + } +} + +// Helper function to mock the state required to test distribute claims +func (s *KeeperTestSuite) SetupTestDistributeClaims() DistributeClaimsTestCase { + // Fund the claim account + claimAddress := s.TestAccs[0] + initialClaimBalance := sdkmath.NewInt(400) + s.FundAccount(claimAddress, sdk.NewCoin(HostIBCDenom, initialClaimBalance)) + + // Create the host zone with a claim address and token denom + hostZone := types.HostZone{ + ClaimAddress: claimAddress.String(), + NativeTokenIbcDenom: HostIBCDenom, + } + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + // Define unbonding records with different statuses + claimableRecordIds := []uint64{1, 3} + unbondingRecords := []types.UnbondingRecord{ + {Id: 1, Status: types.CLAIMABLE}, + {Id: 2, Status: types.UNBONDING_IN_PROGRESS}, + {Id: 3, Status: types.CLAIMABLE}, + {Id: 4, Status: types.UNBONDING_QUEUE}, + } + for _, unbondingRecord := range unbondingRecords { + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, unbondingRecord) + } + + // Define redmeption records across different unbonding records + redemptionRecords := []types.RedemptionRecord{ + {UnbondingRecordId: 1, NativeAmount: sdkmath.NewInt(10)}, // claimable + {UnbondingRecordId: 1, NativeAmount: sdkmath.NewInt(20)}, // claimable + {UnbondingRecordId: 2, NativeAmount: sdkmath.NewInt(30)}, + {UnbondingRecordId: 2, NativeAmount: sdkmath.NewInt(40)}, + {UnbondingRecordId: 3, NativeAmount: sdkmath.NewInt(50)}, // claimable + {UnbondingRecordId: 3, NativeAmount: sdkmath.NewInt(60)}, // claimable + {UnbondingRecordId: 3, NativeAmount: sdkmath.NewInt(70)}, // claimable + {UnbondingRecordId: 4, NativeAmount: sdkmath.NewInt(80)}, + {UnbondingRecordId: 4, NativeAmount: sdkmath.NewInt(90)}, + } + accounts := apptesting.CreateRandomAccounts(len(redemptionRecords)) + expectedFinalClaimBalance := initialClaimBalance.SubRaw(10 + 20 + 50 + 60 + 70) + + // Create a record for each redemption + for i, redemptionRecord := range redemptionRecords { + redemptionRecord.Redeemer = accounts[i].String() + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, redemptionRecord) + } + + return DistributeClaimsTestCase{ + claimAddress: claimAddress, + claimableRecordIds: claimableRecordIds, + expectedFinalClaimBalance: expectedFinalClaimBalance, + } +} + +// The granularity at the redemption record level is covered by TestDistributeClaimsForUnbondingRecord +func (s *KeeperTestSuite) TestDistributeClaims_Success() { + tc := s.SetupTestDistributeClaims() + + // Call distribute again, it should succeed + err := s.App.StakedymKeeper.DistributeClaims(s.Ctx) + s.Require().NoError(err, "no error expected during claim") + + // Confirm the claim balance was depleted + actualClaimBalance := s.App.BankKeeper.GetBalance(s.Ctx, tc.claimAddress, HostIBCDenom) + s.Require().Equal(tc.expectedFinalClaimBalance.Int64(), actualClaimBalance.Amount.Int64(), + "claim balance should have been depleted") + + // Confirm the CLAIMABLE records were archived + activeRecords := s.App.StakedymKeeper.GetAllActiveUnbondingRecords(s.Ctx) + archivedRecords := s.App.StakedymKeeper.GetAllArchivedUnbondingRecords(s.Ctx) + s.Require().Len(activeRecords, 2, "there should only be two remaining active records") + s.Require().Len(archivedRecords, 2, "there should be two archived records") + + archivedIds := []uint64{archivedRecords[0].Id, archivedRecords[1].Id} + s.Require().ElementsMatch(tc.claimableRecordIds, archivedIds, "claimable records should now be archived") +} + +func (s *KeeperTestSuite) TestDistributeClaims_HostHalted() { + s.SetupTestDistributeClaims() + + // Halt the host zone, then attempt to call distribute claims, it should fail + hostZone := s.MustGetHostZone() + hostZone.Halted = true + s.App.StakedymKeeper.SetHostZone(s.Ctx, hostZone) + + err := s.App.StakedymKeeper.DistributeClaims(s.Ctx) + s.Require().ErrorContains(err, "host zone is halted") +} + +func (s *KeeperTestSuite) TestDistributeClaims_InsufficientFunds() { + s.SetupTestDistributeClaims() + + // Pass through the records again and make them all claimable + for _, unbondingRecord := range s.App.StakedymKeeper.GetAllActiveUnbondingRecords(s.Ctx) { + unbondingRecord.Status = types.CLAIMABLE + s.App.StakedymKeeper.SetUnbondingRecord(s.Ctx, unbondingRecord) + } + + // Attempt to distribute, it will error cause there will not be enough funds to cover all records + err := s.App.StakedymKeeper.DistributeClaims(s.Ctx) + s.Require().ErrorContains(err, "insufficient funds") +} + +func (s *KeeperTestSuite) TestDistributeClaims_InvalidClaimAddress() { + s.SetupTestDistributeClaims() + + // Update the claim address so that it is invalid + invalidHostZone := s.MustGetHostZone() + invalidHostZone.ClaimAddress = "invalid_address" + s.App.StakedymKeeper.SetHostZone(s.Ctx, invalidHostZone) + + err := s.App.StakedymKeeper.DistributeClaims(s.Ctx) + s.Require().ErrorContains(err, "invalid host zone claim address invalid_address") +} + +func (s *KeeperTestSuite) TestDistributeClaimsForUnbondingRecord() { + // Fund the claim account + claimAddress := s.TestAccs[0] + redeemerAddress := s.TestAccs[1] + initialClaimBalance := sdkmath.NewInt(100) + s.FundAccount(claimAddress, sdk.NewCoin(HostIBCDenom, initialClaimBalance)) + + // Define all the redemptions + // Unbonding record 1 will be distributed + distributedUnbondingId := uint64(1) + redemptionRecords := []types.RedemptionRecord{ + {UnbondingRecordId: distributedUnbondingId, NativeAmount: sdkmath.NewInt(10)}, // 100 (initial) - 10 = 90 remaining + {UnbondingRecordId: distributedUnbondingId, NativeAmount: sdkmath.NewInt(15)}, // 90 - 15 = 75 remaining + {UnbondingRecordId: 2, NativeAmount: sdkmath.NewInt(10)}, // Different unbonding record ID, skipped + {UnbondingRecordId: distributedUnbondingId, NativeAmount: sdkmath.NewInt(30)}, // 75 - 30 = 45 remaining + {UnbondingRecordId: 3, NativeAmount: sdkmath.NewInt(10)}, // Different unbonding record ID, skipped + {UnbondingRecordId: distributedUnbondingId, NativeAmount: sdkmath.NewInt(8)}, // 45 - 8 = 37 remaining + {UnbondingRecordId: 4, NativeAmount: sdkmath.NewInt(10)}, // Different unbonding record ID, skipped + {UnbondingRecordId: distributedUnbondingId, NativeAmount: sdkmath.NewInt(27)}, // 37 - 27 = 10 remaining (final) + } + accounts := apptesting.CreateRandomAccounts(len(redemptionRecords) + 1) + expectedFinalClaimBalance := initialClaimBalance.SubRaw(10 + 15 + 30 + 8 + 27) + + // Create a record for each redemption + for i, redemptionRecord := range redemptionRecords { + redemptionRecord.Redeemer = accounts[i].String() + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, redemptionRecord) + } + + // Call distribute on the unbonding record in question + err := s.App.StakedymKeeper.DistributeClaimsForUnbondingRecord( + s.Ctx, + HostIBCDenom, + claimAddress, + distributedUnbondingId, + ) + s.Require().NoError(err, "no error expected when distributing claims") + + // Confirm the claim balance was depleted + actualClaimBalance := s.App.BankKeeper.GetBalance(s.Ctx, claimAddress, HostIBCDenom) + s.Require().Equal(expectedFinalClaimBalance.Int64(), actualClaimBalance.Amount.Int64(), + "claim balance should have been depleted") + + // Loop again, confirm all users received their tokens, and that all redemption records were removed + for i, redemption := range redemptionRecords { + if redemption.UnbondingRecordId != distributedUnbondingId { + continue + } + redeemer := accounts[i] + userBalance := s.App.BankKeeper.GetBalance(s.Ctx, redeemer, HostIBCDenom) + s.Require().Equal(redemption.NativeAmount.Int64(), userBalance.Amount.Int64(), + "user %d should have received their native tokens", i) + + _, found := s.App.StakedymKeeper.GetRedemptionRecord(s.Ctx, redemption.UnbondingRecordId, redemption.Redeemer) + s.Require().False(found, "redemption record for unbonding record %d should have been removed", + redemption.UnbondingRecordId) + } + + // Add a record with an amount that would exceed the claim account's remaining balance + exceedBalanceUnbondingId := uint64(100) + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, types.RedemptionRecord{ + UnbondingRecordId: exceedBalanceUnbondingId, + Redeemer: redeemerAddress.String(), + NativeAmount: initialClaimBalance, + }) + + // Add a record with an invalid address + invalidAddressUnbondingId := uint64(200) + s.App.StakedymKeeper.SetRedemptionRecord(s.Ctx, types.RedemptionRecord{ + UnbondingRecordId: invalidAddressUnbondingId, + Redeemer: "invalid_address", + NativeAmount: initialClaimBalance, + }) + + // Attempt to distribute for that record, it should fail + err = s.App.StakedymKeeper.DistributeClaimsForUnbondingRecord( + s.Ctx, + HostIBCDenom, + claimAddress, + exceedBalanceUnbondingId, + ) + s.Require().ErrorContains(err, "insufficient funds") + + // Attempt to distribute for that record, it should fail + err = s.App.StakedymKeeper.DistributeClaimsForUnbondingRecord( + s.Ctx, + HostIBCDenom, + claimAddress, + invalidAddressUnbondingId, + ) + s.Require().ErrorContains(err, "invalid redeemer address") +} diff --git a/x/stakedym/module.go b/x/stakedym/module.go new file mode 100644 index 0000000000..ff7056d38d --- /dev/null +++ b/x/stakedym/module.go @@ -0,0 +1,156 @@ +package stakedym + +import ( + "context" + "encoding/json" + "fmt" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + "github.com/Stride-Labs/stride/v18/x/stakedym/client/cli" + "github.com/Stride-Labs/stride/v18/x/stakedym/keeper" + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface for the capability module. +type AppModuleBasic struct { + cdc codec.BinaryCodec +} + +func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the capability module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) +} + +// RegisterInterfaces registers the module's interface types +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns the capability module's default genesis state. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the capability module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} + +// RegisterRESTRoutes registers the capability module's REST service handlers. +func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) { +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { + panic(err) + } +} + +// GetTxCmd returns the capability module's root tx command. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns the capability module's root query command. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface for the capability module. +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper +} + +func NewAppModule( + cdc codec.Codec, + keeper keeper.Keeper, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + } +} + +// Name returns the capability module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// RegisterServices registers a GRPC query service to respond to the +// module-specific GRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) +} + +// RegisterInvariants registers the capability module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the capability module's genesis initialization It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { + var genState types.GenesisState + // Initialize global index to index in genesis state + cdc.MustUnmarshalJSON(gs, &genState) + + am.keeper.InitGenesis(ctx, genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(genState) +} + +// ConsensusVersion implements ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// BeginBlock executes all ABCI BeginBlock logic respective to the capability module. +func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { + am.keeper.BeginBlocker(ctx) +} + +// EndBlock executes all ABCI EndBlock logic respective to the capability module. It +// returns no validator updates. +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} diff --git a/x/stakedym/types/codec.go b/x/stakedym/types/codec.go new file mode 100644 index 0000000000..1bcae69f56 --- /dev/null +++ b/x/stakedym/types/codec.go @@ -0,0 +1,62 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/legacy" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" + govcodec "github.com/cosmos/cosmos-sdk/x/gov/codec" +) + +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + legacy.RegisterAminoMsg(cdc, &MsgLiquidStake{}, "stakedym/MsgLiquidStake") + legacy.RegisterAminoMsg(cdc, &MsgRedeemStake{}, "stakedym/MsgRedeemStake") + legacy.RegisterAminoMsg(cdc, &MsgConfirmDelegation{}, "stakedym/MsgConfirmDelegation") + legacy.RegisterAminoMsg(cdc, &MsgConfirmUndelegation{}, "stakedym/MsgConfirmUndelegation") + legacy.RegisterAminoMsg(cdc, &MsgConfirmUnbondedTokenSweep{}, "stakedym/MsgConfirmUnbondedTokenSweep") + legacy.RegisterAminoMsg(cdc, &MsgAdjustDelegatedBalance{}, "stakedym/MsgAdjustDelegatedBalance") + legacy.RegisterAminoMsg(cdc, &MsgUpdateInnerRedemptionRateBounds{}, "stakedym/MsgUpdateRedemptionRateBounds") + legacy.RegisterAminoMsg(cdc, &MsgResumeHostZone{}, "stakedym/MsgResumeHostZone") + legacy.RegisterAminoMsg(cdc, &MsgRefreshRedemptionRate{}, "stakedym/MsgRefreshRedemptionRate") + legacy.RegisterAminoMsg(cdc, &MsgOverwriteDelegationRecord{}, "stakedym/MsgOverwriteDelegationRecord") + legacy.RegisterAminoMsg(cdc, &MsgOverwriteUnbondingRecord{}, "stakedym/MsgOverwriteUnbondingRecord") + legacy.RegisterAminoMsg(cdc, &MsgOverwriteRedemptionRecord{}, "stakedym/MsgOverwriteRedemptionRecord") + legacy.RegisterAminoMsg(cdc, &MsgSetOperatorAddress{}, "stakedym/MsgSetOperatorAddress") + +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgLiquidStake{}, + &MsgRedeemStake{}, + &MsgConfirmDelegation{}, + &MsgConfirmUndelegation{}, + &MsgConfirmUnbondedTokenSweep{}, + &MsgAdjustDelegatedBalance{}, + &MsgUpdateInnerRedemptionRateBounds{}, + &MsgResumeHostZone{}, + &MsgRefreshRedemptionRate{}, + &MsgOverwriteDelegationRecord{}, + &MsgOverwriteUnbondingRecord{}, + &MsgOverwriteRedemptionRecord{}, + &MsgSetOperatorAddress{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewAminoCodec(amino) +) + +func init() { + RegisterLegacyAminoCodec(amino) + cryptocodec.RegisterCrypto(amino) + sdk.RegisterLegacyAminoCodec(amino) + + // Register all Amino interfaces and concrete types on the authz and gov Amino codec so that this can later be + // used to properly serialize MsgSubmitProposal instances + RegisterLegacyAminoCodec(govcodec.Amino) +} diff --git a/x/stakedym/types/dymension.go b/x/stakedym/types/dymension.go new file mode 100644 index 0000000000..e2a5bf49f9 --- /dev/null +++ b/x/stakedym/types/dymension.go @@ -0,0 +1,20 @@ +// #nosec G101 +package types + +const ( + DymensionChainId = "dymension_1100-1" + StrideToDymensionTransferChannelId = "channel-197" + DymensionNativeTokenDenom = "adym" + DymensionNativeTokenIBCDenom = "ibc/E1C22332C083574F3418481359733BA8887D171E76C80AD9237422AEABB66018" // #nosec G101 + + DelegationAddressOnDymension = "dym1gl9j2hyyukqvlmzzcxl99mqfgu4y4frgzlv3zz" // C0 + RewardAddressOnDymension = "dym1ww3m6h5e3dk2musft9w8f2zu4rkuxgh6zwu0d0" // C1 + + DepositAddress = "stride1e7j8d6sdq272fqe2jfxjpgcagn04j75w9695fj" // S4 + RedemptionAddress = "stride1jpsnc0ynufa2aheflj6mxzzzsu7nlwqk7ff69n" // S5 + ClaimAddress = "stride1q8juddwptg5yxyghh3n243pp4w8ctpvpmf6ras" // S6 + + SafeAddressOnStride = "stride1sj8gyqeqecqhqu7em67hn2tjzhpkdf8wz5plh7" // S7 + OperatorAddressOnStride = "stride1ghhu67ttgmxrsyxljfl2tysyayswklvxs7pepw" // OP-STRIDE + DymensionUnbondingPeriodSeconds = uint64(21 * 24 * 60 * 60) // 21 days +) diff --git a/x/stakedym/types/errors.go b/x/stakedym/types/errors.go new file mode 100644 index 0000000000..0c8c35c0b9 --- /dev/null +++ b/x/stakedym/types/errors.go @@ -0,0 +1,32 @@ +package types + +import errorsmod "cosmossdk.io/errors" + +var ( + ErrHostZoneNotFound = errorsmod.Register(ModuleName, 1901, "host zone not found") + ErrInvalidHostZone = errorsmod.Register(ModuleName, 1902, "invalid host zone during genesis") + ErrHostZoneHalted = errorsmod.Register(ModuleName, 1903, "host zone is halted") + ErrHostZoneNotHalted = errorsmod.Register(ModuleName, 1904, "host zone is not halted") + ErrInvalidBounds = errorsmod.Register(ModuleName, 1905, "invalid inner bounds") + ErrRedemptionRateOutsideSafetyBounds = errorsmod.Register(ModuleName, 1906, "host zone redemption rate outside safety bounds") + ErrInvalidRedemptionRateBounds = errorsmod.Register(ModuleName, 1907, "invalid host zone redemption rate inner bounds") + ErrDelegationRecordNotFound = errorsmod.Register(ModuleName, 1908, "delegation record not found") + ErrDelegationRecordInvalidState = errorsmod.Register(ModuleName, 1909, "delegation record in incorrect state") + ErrDelegationRecordAlreadyExists = errorsmod.Register(ModuleName, 1910, "delegation record already exists") + ErrUnbondingRecordNotFound = errorsmod.Register(ModuleName, 1911, "unbonding record not found") + ErrUnbondingRecordAlreadyExists = errorsmod.Register(ModuleName, 1912, "unbonding record already exists") + ErrBrokenUnbondingRecordInvariant = errorsmod.Register(ModuleName, 1913, "broken unbonding record invariant") + ErrInvalidUnbondingRecord = errorsmod.Register(ModuleName, 1914, "unbonding record in incorrect state") + ErrRedemptionRecordNotFound = errorsmod.Register(ModuleName, 1915, "redemption record not found") + ErrUnbondAmountToLarge = errorsmod.Register(ModuleName, 1916, "unbonding more than exists on host zone") + ErrInvalidAmountBelowMinimum = errorsmod.Register(ModuleName, 1917, "amount provided is too small") + ErrNegativeNotAllowed = errorsmod.Register(ModuleName, 1918, "negative value not allowed") + ErrInsufficientFunds = errorsmod.Register(ModuleName, 1919, "not enough funds") + ErrInvalidTxHash = errorsmod.Register(ModuleName, 1920, "tx hash is invalid") + ErrInvalidAdmin = errorsmod.Register(ModuleName, 1921, "signer is not an admin") + ErrInvalidArgument = errorsmod.Register(ModuleName, 1922, "argument is not valid") + ErrInvariantBroken = errorsmod.Register(ModuleName, 1923, "invariant broken") + ErrDivisionByZero = errorsmod.Register(ModuleName, 1924, "division by zero") + ErrInvalidRecordType = errorsmod.Register(ModuleName, 1925, "invalid record type") + ErrInvalidGenesisRecords = errorsmod.Register(ModuleName, 1926, "invalid records during genesis") +) diff --git a/x/stakedym/types/events.go b/x/stakedym/types/events.go new file mode 100644 index 0000000000..d48ea87c8a --- /dev/null +++ b/x/stakedym/types/events.go @@ -0,0 +1,25 @@ +// #nosec G101 +package types + +const ( + EventTypeLiquidStakeRequest = "liquid_stake" + EventTypeRedeemStakeRequest = "redeem_stake" + EventTypeConfirmDelegationResponse = "confirm_delegation" + EventTypeConfirmUnbondedTokenSweep = "confirm_unbonded_token_sweep" + EventTypeConfirmUndelegation = "confirm_undelegation" + + AttributeKeyHostZone = "host_zone" + AttributeKeyRedemptionRate = "redemption_rate" + AttributeKeyLiquidStaker = "liquid_staker" + AttributeKeyRedeemer = "redeemer" + AttributeKeyNativeBaseDenom = "native_base_denom" + AttributeKeyNativeIBCDenom = "native_ibc_denom" + AttributeKeyNativeAmount = "native_amount" + AttributeKeyStTokenAmount = "sttoken_amount" + AttributeRecordId = "record_id" + AttributeDelegationNativeAmount = "delegation_native_amount" + AttributeUndelegationNativeAmount = "undelegation_native_amount" + AttributeTxHash = "tx_hash" + AttributeSender = "sender" + EventTypeHostZoneHalt = "host_zone_halt" +) diff --git a/x/stakedym/types/expected_keepers.go b/x/stakedym/types/expected_keepers.go new file mode 100644 index 0000000000..c39d87c3cf --- /dev/null +++ b/x/stakedym/types/expected_keepers.go @@ -0,0 +1,43 @@ +package types + +import ( + context "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" +) + +// Required AccountKeeper functions +type AccountKeeper interface { + GetModuleAccount(ctx sdk.Context, moduleName string) authtypes.ModuleAccountI + GetModuleAddress(name string) sdk.AccAddress +} + +// Required BankKeeper functions +type BankKeeper interface { + MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error + GetSupply(ctx sdk.Context, denom string) sdk.Coin + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddress sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) error +} + +// Required TransferKeeper functions +type TransferKeeper interface { + Transfer(goCtx context.Context, msg *transfertypes.MsgTransfer) (*transfertypes.MsgTransferResponse, error) +} + +// Required RatelimitKeeper functions +type RatelimitKeeper interface { + AddDenomToBlacklist(ctx sdk.Context, denom string) + RemoveDenomFromBlacklist(ctx sdk.Context, denom string) +} + +// Required ICAOracleKeeper functions +type ICAOracleKeeper interface { + QueueMetricUpdate(ctx sdk.Context, key, value, metricType, attributes string) +} diff --git a/x/stakedym/types/genesis.go b/x/stakedym/types/genesis.go new file mode 100644 index 0000000000..d672178770 --- /dev/null +++ b/x/stakedym/types/genesis.go @@ -0,0 +1,71 @@ +package types + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// DefaultGenesis returns the default genesis state +// Only the host zone and accumulator record are needed at default genesis, +// other record should be empty +func DefaultGenesis() *GenesisState { + return &GenesisState{ + HostZone: HostZone{ + ChainId: DymensionChainId, + NativeTokenDenom: DymensionNativeTokenDenom, + NativeTokenIbcDenom: DymensionNativeTokenIBCDenom, + TransferChannelId: StrideToDymensionTransferChannelId, + UnbondingPeriodSeconds: DymensionUnbondingPeriodSeconds, + + // on dymension + DelegationAddress: DelegationAddressOnDymension, + RewardAddress: RewardAddressOnDymension, + + // functional accounts on stride + DepositAddress: DepositAddress, + RedemptionAddress: RedemptionAddress, + ClaimAddress: ClaimAddress, + + // management accounts on stride + SafeAddressOnStride: SafeAddressOnStride, + OperatorAddressOnStride: OperatorAddressOnStride, + + RedemptionRate: sdk.OneDec(), + LastRedemptionRate: sdk.OneDec(), + MinRedemptionRate: sdk.MustNewDecFromStr("0.95"), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.1"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.95"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.1"), + DelegatedBalance: sdkmath.ZeroInt(), + Halted: false, + }, + UnbondingRecords: []UnbondingRecord{ + { + Id: 1, + Status: ACCUMULATING_REDEMPTIONS, + NativeAmount: sdkmath.ZeroInt(), + StTokenAmount: sdkmath.ZeroInt(), + }, + }, + } +} + +// Validates the host zone and records in the genesis state +func (gs GenesisState) Validate() error { + if err := gs.HostZone.ValidateGenesis(); err != nil { + return err + } + if err := ValidateDelegationRecordGenesis(gs.DelegationRecords); err != nil { + return err + } + if err := ValidateUnbondingRecordGenesis(gs.UnbondingRecords); err != nil { + return err + } + if err := ValidateRedemptionRecordGenesis(gs.RedemptionRecords); err != nil { + return err + } + if err := ValidateSlashRecordGenesis(gs.SlashRecords); err != nil { + return err + } + return nil +} diff --git a/x/stakedym/types/genesis.pb.go b/x/stakedym/types/genesis.pb.go new file mode 100644 index 0000000000..5e86dbbe14 --- /dev/null +++ b/x/stakedym/types/genesis.pb.go @@ -0,0 +1,1063 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: stride/stakedym/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the stakedym module parameters. +type Params struct { +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_c9f69b9927e2a0f2, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +// TransferInProgressRecordIds stores record IDs for delegation records +// that have a transfer in progress +type TransferInProgressRecordIds struct { + ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + Sequence uint64 `protobuf:"varint,2,opt,name=sequence,proto3" json:"sequence,omitempty"` + RecordId uint64 `protobuf:"varint,3,opt,name=record_id,json=recordId,proto3" json:"record_id,omitempty"` +} + +func (m *TransferInProgressRecordIds) Reset() { *m = TransferInProgressRecordIds{} } +func (m *TransferInProgressRecordIds) String() string { return proto.CompactTextString(m) } +func (*TransferInProgressRecordIds) ProtoMessage() {} +func (*TransferInProgressRecordIds) Descriptor() ([]byte, []int) { + return fileDescriptor_c9f69b9927e2a0f2, []int{1} +} +func (m *TransferInProgressRecordIds) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TransferInProgressRecordIds) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TransferInProgressRecordIds.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TransferInProgressRecordIds) XXX_Merge(src proto.Message) { + xxx_messageInfo_TransferInProgressRecordIds.Merge(m, src) +} +func (m *TransferInProgressRecordIds) XXX_Size() int { + return m.Size() +} +func (m *TransferInProgressRecordIds) XXX_DiscardUnknown() { + xxx_messageInfo_TransferInProgressRecordIds.DiscardUnknown(m) +} + +var xxx_messageInfo_TransferInProgressRecordIds proto.InternalMessageInfo + +func (m *TransferInProgressRecordIds) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +func (m *TransferInProgressRecordIds) GetSequence() uint64 { + if m != nil { + return m.Sequence + } + return 0 +} + +func (m *TransferInProgressRecordIds) GetRecordId() uint64 { + if m != nil { + return m.RecordId + } + return 0 +} + +// GenesisState defines the stakedym module's genesis state. +type GenesisState struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params" yaml:"params"` + HostZone HostZone `protobuf:"bytes,2,opt,name=host_zone,json=hostZone,proto3" json:"host_zone"` + DelegationRecords []DelegationRecord `protobuf:"bytes,3,rep,name=delegation_records,json=delegationRecords,proto3" json:"delegation_records"` + UnbondingRecords []UnbondingRecord `protobuf:"bytes,4,rep,name=unbonding_records,json=unbondingRecords,proto3" json:"unbonding_records"` + RedemptionRecords []RedemptionRecord `protobuf:"bytes,5,rep,name=redemption_records,json=redemptionRecords,proto3" json:"redemption_records"` + SlashRecords []SlashRecord `protobuf:"bytes,6,rep,name=slash_records,json=slashRecords,proto3" json:"slash_records"` + TransferInProgressRecordIds []TransferInProgressRecordIds `protobuf:"bytes,7,rep,name=transfer_in_progress_record_ids,json=transferInProgressRecordIds,proto3" json:"transfer_in_progress_record_ids"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_c9f69b9927e2a0f2, []int{2} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetHostZone() HostZone { + if m != nil { + return m.HostZone + } + return HostZone{} +} + +func (m *GenesisState) GetDelegationRecords() []DelegationRecord { + if m != nil { + return m.DelegationRecords + } + return nil +} + +func (m *GenesisState) GetUnbondingRecords() []UnbondingRecord { + if m != nil { + return m.UnbondingRecords + } + return nil +} + +func (m *GenesisState) GetRedemptionRecords() []RedemptionRecord { + if m != nil { + return m.RedemptionRecords + } + return nil +} + +func (m *GenesisState) GetSlashRecords() []SlashRecord { + if m != nil { + return m.SlashRecords + } + return nil +} + +func (m *GenesisState) GetTransferInProgressRecordIds() []TransferInProgressRecordIds { + if m != nil { + return m.TransferInProgressRecordIds + } + return nil +} + +func init() { + proto.RegisterType((*Params)(nil), "stride.stakedym.Params") + proto.RegisterType((*TransferInProgressRecordIds)(nil), "stride.stakedym.TransferInProgressRecordIds") + proto.RegisterType((*GenesisState)(nil), "stride.stakedym.GenesisState") +} + +func init() { proto.RegisterFile("stride/stakedym/genesis.proto", fileDescriptor_c9f69b9927e2a0f2) } + +var fileDescriptor_c9f69b9927e2a0f2 = []byte{ + // 480 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x93, 0x41, 0x6f, 0xd3, 0x30, + 0x14, 0xc7, 0x1b, 0x56, 0x4a, 0xeb, 0x6e, 0x82, 0x59, 0x20, 0x4a, 0xcb, 0xd2, 0x92, 0x53, 0x0f, + 0x90, 0x88, 0x72, 0x41, 0x88, 0xd3, 0x84, 0x18, 0x95, 0x76, 0x98, 0x52, 0xe0, 0xb0, 0x4b, 0xe4, + 0xd6, 0x26, 0x89, 0x68, 0xec, 0xe0, 0xe7, 0xa0, 0x95, 0x4f, 0xc1, 0xc7, 0xda, 0x71, 0x47, 0x0e, + 0x68, 0x42, 0xed, 0x37, 0xe0, 0x13, 0xa0, 0xc4, 0x6e, 0xa6, 0x34, 0x62, 0x37, 0xfb, 0xbd, 0xff, + 0xfb, 0xbd, 0xbf, 0xad, 0xf7, 0xd0, 0x11, 0x28, 0x19, 0x53, 0xe6, 0x81, 0x22, 0x5f, 0x19, 0x5d, + 0x25, 0x5e, 0xc8, 0x38, 0x83, 0x18, 0xdc, 0x54, 0x0a, 0x25, 0xf0, 0x7d, 0x9d, 0x76, 0xb7, 0xe9, + 0xfe, 0xc3, 0x50, 0x84, 0xa2, 0xc8, 0x79, 0xf9, 0x49, 0xcb, 0xfa, 0xf6, 0x2e, 0x65, 0x7b, 0xd0, + 0x79, 0xa7, 0x8d, 0x5a, 0x67, 0x44, 0x92, 0x04, 0x9c, 0x0c, 0x0d, 0x3e, 0x4a, 0xc2, 0xe1, 0x0b, + 0x93, 0x53, 0x7e, 0x26, 0x45, 0x28, 0x19, 0x80, 0xcf, 0x16, 0x42, 0xd2, 0x29, 0x05, 0x7c, 0x84, + 0xd0, 0x22, 0x22, 0x9c, 0xb3, 0x65, 0x10, 0xd3, 0x9e, 0x35, 0xb2, 0xc6, 0x1d, 0xbf, 0x63, 0x22, + 0x53, 0x8a, 0xfb, 0xa8, 0x0d, 0xec, 0x5b, 0xc6, 0xf8, 0x82, 0xf5, 0xee, 0x8c, 0xac, 0x71, 0xd3, + 0x2f, 0xef, 0x78, 0x80, 0x3a, 0xb2, 0xe0, 0xe4, 0x95, 0x7b, 0x3a, 0x29, 0x0d, 0xd8, 0xf9, 0xdd, + 0x44, 0xfb, 0x27, 0xfa, 0x65, 0x33, 0x45, 0x14, 0xc3, 0xef, 0x51, 0x2b, 0x2d, 0x1c, 0x15, 0x4d, + 0xba, 0x93, 0xc7, 0xee, 0xce, 0x4b, 0x5d, 0x6d, 0xf8, 0xf8, 0xd1, 0xe5, 0xf5, 0xb0, 0xf1, 0xf7, + 0x7a, 0x78, 0xb0, 0x22, 0xc9, 0xf2, 0x8d, 0xa3, 0x8b, 0x1c, 0xdf, 0x54, 0xe3, 0xb7, 0xa8, 0x13, + 0x09, 0x50, 0xc1, 0x0f, 0xc1, 0xb5, 0xa5, 0xee, 0xe4, 0x49, 0x0d, 0xf5, 0x41, 0x80, 0x3a, 0x17, + 0x9c, 0x1d, 0x37, 0x73, 0x98, 0xdf, 0x8e, 0xcc, 0x1d, 0x7f, 0x46, 0x98, 0xb2, 0x25, 0x0b, 0x89, + 0x8a, 0x05, 0x0f, 0xb4, 0x5b, 0xe8, 0xed, 0x8d, 0xf6, 0xc6, 0xdd, 0xc9, 0xb3, 0x1a, 0xe6, 0x5d, + 0x29, 0xd5, 0x1f, 0x66, 0x70, 0x87, 0x74, 0x27, 0x0e, 0x78, 0x86, 0x0e, 0x33, 0x3e, 0x17, 0x9c, + 0xc6, 0x3c, 0x2c, 0xb1, 0xcd, 0x02, 0x3b, 0xaa, 0x61, 0x3f, 0x6d, 0x95, 0x15, 0xea, 0x83, 0xac, + 0x1a, 0x86, 0xdc, 0xac, 0x64, 0x94, 0x25, 0x69, 0xc5, 0xec, 0xdd, 0xff, 0x98, 0xf5, 0x4b, 0x69, + 0xd5, 0xac, 0xdc, 0x89, 0x03, 0x3e, 0x41, 0x07, 0xb0, 0x24, 0x10, 0x95, 0xc8, 0x56, 0x81, 0x7c, + 0x5a, 0x43, 0xce, 0x72, 0x55, 0x85, 0xb6, 0x0f, 0x37, 0x21, 0xc0, 0x17, 0x68, 0xa8, 0xcc, 0x6c, + 0x05, 0x31, 0x0f, 0x52, 0x33, 0x5d, 0x41, 0x39, 0x16, 0xd0, 0xbb, 0x57, 0xa0, 0x9f, 0xd7, 0xd0, + 0xb7, 0xcc, 0xa4, 0x69, 0x35, 0x50, 0xb7, 0x48, 0x4e, 0x2f, 0xd7, 0xb6, 0x75, 0xb5, 0xb6, 0xad, + 0x3f, 0x6b, 0xdb, 0xfa, 0xb9, 0xb1, 0x1b, 0x57, 0x1b, 0xbb, 0xf1, 0x6b, 0x63, 0x37, 0xce, 0x27, + 0x61, 0xac, 0xa2, 0x6c, 0xee, 0x2e, 0x44, 0xe2, 0xcd, 0x8a, 0xa6, 0x2f, 0x4e, 0xc9, 0x1c, 0x3c, + 0xb3, 0x30, 0xdf, 0x5f, 0xbe, 0xf6, 0x2e, 0x6e, 0xd6, 0x46, 0xad, 0x52, 0x06, 0xf3, 0x56, 0xb1, + 0x34, 0xaf, 0xfe, 0x05, 0x00, 0x00, 0xff, 0xff, 0xcd, 0x6b, 0xe1, 0x0c, 0x9c, 0x03, 0x00, 0x00, +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *TransferInProgressRecordIds) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TransferInProgressRecordIds) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TransferInProgressRecordIds) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.RecordId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.RecordId)) + i-- + dAtA[i] = 0x18 + } + if m.Sequence != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.Sequence)) + i-- + dAtA[i] = 0x10 + } + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TransferInProgressRecordIds) > 0 { + for iNdEx := len(m.TransferInProgressRecordIds) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TransferInProgressRecordIds[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + } + if len(m.SlashRecords) > 0 { + for iNdEx := len(m.SlashRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SlashRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.RedemptionRecords) > 0 { + for iNdEx := len(m.RedemptionRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RedemptionRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + if len(m.UnbondingRecords) > 0 { + for iNdEx := len(m.UnbondingRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.UnbondingRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.DelegationRecords) > 0 { + for iNdEx := len(m.DelegationRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DelegationRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + { + size, err := m.HostZone.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *TransferInProgressRecordIds) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.Sequence != 0 { + n += 1 + sovGenesis(uint64(m.Sequence)) + } + if m.RecordId != 0 { + n += 1 + sovGenesis(uint64(m.RecordId)) + } + return n +} + +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + l = m.HostZone.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.DelegationRecords) > 0 { + for _, e := range m.DelegationRecords { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.UnbondingRecords) > 0 { + for _, e := range m.UnbondingRecords { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.RedemptionRecords) > 0 { + for _, e := range m.RedemptionRecords { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.SlashRecords) > 0 { + for _, e := range m.SlashRecords { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.TransferInProgressRecordIds) > 0 { + for _, e := range m.TransferInProgressRecordIds { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TransferInProgressRecordIds) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TransferInProgressRecordIds: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TransferInProgressRecordIds: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) + } + m.Sequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RecordId", wireType) + } + m.RecordId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RecordId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostZone", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.HostZone.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegationRecords", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegationRecords = append(m.DelegationRecords, DelegationRecord{}) + if err := m.DelegationRecords[len(m.DelegationRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingRecords", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UnbondingRecords = append(m.UnbondingRecords, UnbondingRecord{}) + if err := m.UnbondingRecords[len(m.UnbondingRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RedemptionRecords", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RedemptionRecords = append(m.RedemptionRecords, RedemptionRecord{}) + if err := m.RedemptionRecords[len(m.RedemptionRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SlashRecords", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SlashRecords = append(m.SlashRecords, SlashRecord{}) + if err := m.SlashRecords[len(m.SlashRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TransferInProgressRecordIds", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TransferInProgressRecordIds = append(m.TransferInProgressRecordIds, TransferInProgressRecordIds{}) + if err := m.TransferInProgressRecordIds[len(m.TransferInProgressRecordIds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/stakedym/types/host_zone.go b/x/stakedym/types/host_zone.go new file mode 100644 index 0000000000..c5b9ee25e1 --- /dev/null +++ b/x/stakedym/types/host_zone.go @@ -0,0 +1,125 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" +) + +// Helper fucntion to validate a host zone is properly initialized +// during genesis +func (h HostZone) ValidateGenesis() error { + // Validate that the chain ID is provided + if h.ChainId == "" { + return ErrInvalidHostZone.Wrap("chain-id must be specified") + } + if h.TransferChannelId == "" { + return ErrInvalidHostZone.Wrap("transfer channel-id must be specified") + } + + // Validate that the token denom's are provided and that the IBC denom matches + // the hash built from the denom and transfer channel + if h.NativeTokenDenom == "" { + return ErrInvalidHostZone.Wrap("native token denom must be specified") + } + if h.NativeTokenIbcDenom == "" { + return ErrInvalidHostZone.Wrap("native token ibc denom must be specified") + } + + ibcDenomTracePrefix := transfertypes.GetDenomPrefix(transfertypes.PortID, h.TransferChannelId) + expectedIbcDenom := transfertypes.ParseDenomTrace(ibcDenomTracePrefix + h.NativeTokenDenom).IBCDenom() + if h.NativeTokenIbcDenom != expectedIbcDenom { + return ErrInvalidHostZone.Wrapf( + "native token ibc denom did not match hash generated"+ + "from channel (%s) and denom (%s). Provided: %s, Expected: %s", + h.TransferChannelId, h.NativeTokenDenom, h.NativeTokenIbcDenom, expectedIbcDenom, + ) + } + + // Validate all the addresses are provided + if h.DelegationAddress == "" { + return ErrInvalidHostZone.Wrap("delegation address must be specified") + } + if h.RewardAddress == "" { + return ErrInvalidHostZone.Wrap("reward address must be specified") + } + if h.DepositAddress == "" { + return ErrInvalidHostZone.Wrap("deposit address must be specified") + } + if h.RedemptionAddress == "" { + return ErrInvalidHostZone.Wrap("redemption address must be specified") + } + if h.ClaimAddress == "" { + return ErrInvalidHostZone.Wrap("claim address must be specified") + } + if h.OperatorAddressOnStride == "" { + return ErrInvalidHostZone.Wrap("operator address must be specified") + } + if h.SafeAddressOnStride == "" { + return ErrInvalidHostZone.Wrap("safe address must be specified") + } + + // Validate all the stride addresses are valid bech32 addresses + if _, err := sdk.AccAddressFromBech32(h.DepositAddress); err != nil { + return errorsmod.Wrapf(err, "invalid deposit address") + } + if _, err := sdk.AccAddressFromBech32(h.RedemptionAddress); err != nil { + return errorsmod.Wrapf(err, "invalid redemption address") + } + if _, err := sdk.AccAddressFromBech32(h.ClaimAddress); err != nil { + return errorsmod.Wrapf(err, "invalid claim address") + } + if _, err := sdk.AccAddressFromBech32(h.OperatorAddressOnStride); err != nil { + return errorsmod.Wrapf(err, "invalid operator address") + } + if _, err := sdk.AccAddressFromBech32(h.SafeAddressOnStride); err != nil { + return errorsmod.Wrapf(err, "invalid safe address") + } + + // Validate the redemption rate bounds are set properly + if !h.RedemptionRate.IsPositive() { + return ErrInvalidHostZone.Wrap("redemption rate must be positive") + } + if err := h.ValidateRedemptionRateBoundsInitalized(); err != nil { + return err + } + + // Validate unbonding period is set + if h.UnbondingPeriodSeconds == 0 { + return ErrInvalidHostZone.Wrap("unbonding period must be set") + } + + return nil +} + +// Verify the redemption rate bounds are set properly on the host zone +func (h HostZone) ValidateRedemptionRateBoundsInitalized() error { + // Validate outer bounds are set + if h.MinRedemptionRate.IsNil() || !h.MinRedemptionRate.IsPositive() { + return ErrInvalidRedemptionRateBounds.Wrapf("min outer redemption rate bound not set") + } + if h.MaxRedemptionRate.IsNil() || !h.MaxRedemptionRate.IsPositive() { + return ErrInvalidRedemptionRateBounds.Wrapf("max outer redemption rate bound not set") + } + + // Validate inner bounds set + if h.MinInnerRedemptionRate.IsNil() || !h.MinInnerRedemptionRate.IsPositive() { + return ErrInvalidRedemptionRateBounds.Wrapf("min inner redemption rate bound not set") + } + if h.MaxInnerRedemptionRate.IsNil() || !h.MaxInnerRedemptionRate.IsPositive() { + return ErrInvalidRedemptionRateBounds.Wrapf("max inner redemption rate bound not set") + } + + // Validate inner bounds are within outer bounds + if h.MinInnerRedemptionRate.LT(h.MinRedemptionRate) { + return ErrInvalidRedemptionRateBounds.Wrapf("min inner redemption rate bound outside of min outer bound") + } + if h.MaxInnerRedemptionRate.GT(h.MaxRedemptionRate) { + return ErrInvalidRedemptionRateBounds.Wrapf("max inner redemption rate bound outside of max outer bound") + } + if h.MinInnerRedemptionRate.GT(h.MaxInnerRedemptionRate) { + return ErrInvalidRedemptionRateBounds.Wrapf("min inner redemption rate greater than max inner bound") + } + + return nil +} diff --git a/x/stakedym/types/host_zone_test.go b/x/stakedym/types/host_zone_test.go new file mode 100644 index 0000000000..d32ce3ab40 --- /dev/null +++ b/x/stakedym/types/host_zone_test.go @@ -0,0 +1,348 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + "github.com/stretchr/testify/require" + + "github.com/Stride-Labs/stride/v18/app/apptesting" + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +const ( + Uninitialized = "uninitialized" + UninitializedInt = 999 +) + +// Helper function to fill in individual fields +// If the field is empty, replace with a valid value +// If the field is "uninitialized", replace with an empty value +func fillDefaultValue(currentValue, defaultValidValue string) string { + if currentValue == "" { + return defaultValidValue + } else if currentValue == Uninitialized { + return "" + } + return currentValue +} + +// Helper function to fill in default values for the host zone struct +// if they're not specified in the test case +func fillDefaultHostZone(hostZone types.HostZone) types.HostZone { + validChannelId := "channel-0" + validDenom := "denom" + + hostZone.ChainId = fillDefaultValue(hostZone.ChainId, "chain-0") + hostZone.TransferChannelId = fillDefaultValue(hostZone.TransferChannelId, validChannelId) + hostZone.NativeTokenDenom = fillDefaultValue(hostZone.NativeTokenDenom, validDenom) + + ibcDenomTracePrefix := transfertypes.GetDenomPrefix(transfertypes.PortID, validChannelId) + defaultIbcDenom := transfertypes.ParseDenomTrace(ibcDenomTracePrefix + validDenom).IBCDenom() + hostZone.NativeTokenIbcDenom = fillDefaultValue(hostZone.NativeTokenIbcDenom, defaultIbcDenom) + + hostZone.DelegationAddress = fillDefaultValue(hostZone.DelegationAddress, "dymXXX") + hostZone.RewardAddress = fillDefaultValue(hostZone.RewardAddress, "dymXXX") + + validAddress := apptesting.CreateRandomAccounts(1)[0].String() + hostZone.DepositAddress = fillDefaultValue(hostZone.DepositAddress, validAddress) + hostZone.RedemptionAddress = fillDefaultValue(hostZone.RedemptionAddress, validAddress) + hostZone.ClaimAddress = fillDefaultValue(hostZone.ClaimAddress, validAddress) + hostZone.OperatorAddressOnStride = fillDefaultValue(hostZone.OperatorAddressOnStride, validAddress) + hostZone.SafeAddressOnStride = fillDefaultValue(hostZone.SafeAddressOnStride, validAddress) + + if hostZone.RedemptionRate.IsNil() { + hostZone.RedemptionRate = sdk.OneDec() + hostZone.MinRedemptionRate = sdk.MustNewDecFromStr("0.8") + hostZone.MinInnerRedemptionRate = sdk.MustNewDecFromStr("0.9") + hostZone.MaxInnerRedemptionRate = sdk.MustNewDecFromStr("1.1") + hostZone.MaxRedemptionRate = sdk.MustNewDecFromStr("1.2") + } + + if hostZone.UnbondingPeriodSeconds == UninitializedInt { + hostZone.UnbondingPeriodSeconds = 0 // invalid + } else { + hostZone.UnbondingPeriodSeconds = 21 // valid + } + + return hostZone +} + +func TestValidateHostZoneGenesis(t *testing.T) { + // For each test case, assume all excluded values are valid + // (they'll be filled in downstream) + testCases := []struct { + name string + hostZone types.HostZone + expectedError string + }{ + { + name: "valid host zone", + hostZone: types.HostZone{}, + }, + { + name: "missing chain-id", + hostZone: types.HostZone{ + ChainId: Uninitialized, + }, + expectedError: "chain-id must be specified", + }, + { + name: "missing transfer channel-id", + hostZone: types.HostZone{ + TransferChannelId: Uninitialized, + }, + expectedError: "transfer channel-id must be specified", + }, + { + name: "missing token denom", + hostZone: types.HostZone{ + NativeTokenDenom: Uninitialized, + }, + expectedError: "native token denom must be specified", + }, + { + name: "missing token ibc denom", + hostZone: types.HostZone{ + NativeTokenIbcDenom: Uninitialized, + }, + expectedError: "native token ibc denom must be specified", + }, + { + name: "ibc denom mismatch", + hostZone: types.HostZone{ + NativeTokenIbcDenom: "ibc/XXX", + }, + expectedError: "native token ibc denom did not match hash generated", + }, + { + name: "missing delegation address", + hostZone: types.HostZone{ + DelegationAddress: Uninitialized, + }, + expectedError: "delegation address must be specified", + }, + { + name: "missing reward address", + hostZone: types.HostZone{ + RewardAddress: Uninitialized, + }, + expectedError: "reward address must be specified", + }, + { + name: "missing deposit address", + hostZone: types.HostZone{ + DepositAddress: Uninitialized, + }, + expectedError: "deposit address must be specified", + }, + { + name: "missing redemption address", + hostZone: types.HostZone{ + RedemptionAddress: Uninitialized, + }, + expectedError: "redemption address must be specified", + }, + { + name: "missing claim address", + hostZone: types.HostZone{ + ClaimAddress: Uninitialized, + }, + expectedError: "claim address must be specified", + }, + { + name: "missing operator address", + hostZone: types.HostZone{ + OperatorAddressOnStride: Uninitialized, + }, + expectedError: "operator address must be specified", + }, + { + name: "missing safe address", + hostZone: types.HostZone{ + SafeAddressOnStride: Uninitialized, + }, + expectedError: "safe address must be specified", + }, + { + name: "invalid deposit address", + hostZone: types.HostZone{ + DepositAddress: "invalid_address", + }, + expectedError: "invalid deposit address", + }, + { + name: "invalid redemption address", + hostZone: types.HostZone{ + RedemptionAddress: "invalid_address", + }, + expectedError: "invalid redemption address", + }, + { + name: "invalid claim address", + hostZone: types.HostZone{ + ClaimAddress: "invalid_address", + }, + expectedError: "invalid claim address", + }, + { + name: "invalid operator address", + hostZone: types.HostZone{ + OperatorAddressOnStride: "invalid_address", + }, + expectedError: "invalid operator address", + }, + { + name: "invalid safe address", + hostZone: types.HostZone{ + SafeAddressOnStride: "invalid_address", + }, + expectedError: "invalid safe address", + }, + { + name: "invalid redemption rate", + hostZone: types.HostZone{ + RedemptionRate: sdk.OneDec().Neg(), + }, + expectedError: "redemption rate must be positive", + }, + { + name: "invalid redemption rate bounds", + hostZone: types.HostZone{ + RedemptionRate: sdk.OneDec(), + MinRedemptionRate: sdk.MustNewDecFromStr("1.1"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.9"), + }, + expectedError: "invalid host zone redemption rate inner bounds", + }, + { + name: "missing unbonding period", + hostZone: types.HostZone{ + UnbondingPeriodSeconds: UninitializedInt, + }, + expectedError: "unbonding period must be set", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + hostZone := fillDefaultHostZone(tc.hostZone) + err := hostZone.ValidateGenesis() + + if tc.expectedError == "" { + require.NoError(t, err, "no error expected") + } else { + require.ErrorContains(t, err, tc.expectedError) + } + }) + } +} + +func TestValidateRedemptionRateBoundsInitalized(t *testing.T) { + testCases := []struct { + name string + hostZone types.HostZone + valid bool + }{ + { + name: "valid bounds", + hostZone: types.HostZone{ + MinRedemptionRate: sdk.MustNewDecFromStr("0.8"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.9"), + RedemptionRate: sdk.MustNewDecFromStr("1.0"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.1"), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2"), + }, + valid: true, + }, + { + name: "min outer negative", + hostZone: types.HostZone{ + MinRedemptionRate: sdk.MustNewDecFromStr("0.8").Neg(), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.9"), + RedemptionRate: sdk.MustNewDecFromStr("1.0"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.1"), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2"), + }, + valid: false, + }, + { + name: "min inner negative", + hostZone: types.HostZone{ + MinRedemptionRate: sdk.MustNewDecFromStr("0.8"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.9").Neg(), + RedemptionRate: sdk.MustNewDecFromStr("1.0"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.1"), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2"), + }, + valid: false, + }, + { + name: "max inner negative", + hostZone: types.HostZone{ + MinRedemptionRate: sdk.MustNewDecFromStr("0.8"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.9"), + RedemptionRate: sdk.MustNewDecFromStr("1.0"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.1").Neg(), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2"), + }, + valid: false, + }, + { + name: "max outer negative", + hostZone: types.HostZone{ + MinRedemptionRate: sdk.MustNewDecFromStr("0.8"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.9"), + RedemptionRate: sdk.MustNewDecFromStr("1.0"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.1"), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2").Neg(), + }, + valid: false, + }, + { + name: "max inner outside outer", + hostZone: types.HostZone{ + MinRedemptionRate: sdk.MustNewDecFromStr("0.8"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.9"), + RedemptionRate: sdk.MustNewDecFromStr("1.0"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.3"), // <-- + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2"), + }, + valid: false, + }, + { + name: "min inner outside outer", + hostZone: types.HostZone{ + MinRedemptionRate: sdk.MustNewDecFromStr("0.8"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("0.7"), // <-- + RedemptionRate: sdk.MustNewDecFromStr("1.0"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.1"), + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2"), + }, + valid: false, + }, + { + name: "min inner greater than min outer", + hostZone: types.HostZone{ + MinRedemptionRate: sdk.MustNewDecFromStr("0.8"), + MinInnerRedemptionRate: sdk.MustNewDecFromStr("1.1"), // <-- + RedemptionRate: sdk.MustNewDecFromStr("1.0"), + MaxInnerRedemptionRate: sdk.MustNewDecFromStr("0.9"), // <-- + MaxRedemptionRate: sdk.MustNewDecFromStr("1.2"), + }, + valid: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.hostZone.ValidateRedemptionRateBoundsInitalized() + if tc.valid { + require.NoError(t, err, "no error expected") + } else { + require.ErrorIs(t, err, types.ErrInvalidRedemptionRateBounds) + } + }) + } +} diff --git a/x/stakedym/types/keys.go b/x/stakedym/types/keys.go new file mode 100644 index 0000000000..2c46376253 --- /dev/null +++ b/x/stakedym/types/keys.go @@ -0,0 +1,55 @@ +package types + +import "encoding/binary" + +const ( + ModuleName = "stakedym" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // RouterKey defines the routing key + RouterKey = ModuleName + + // Module Account for Fee Collection + FeeAddress = "stakedym_fee_address" +) + +var ( + // Prefix store keys + HostZoneKey = []byte("host-zone") + DelegationRecordsKeyPrefix = []byte("delegation-records-active") + DelegationRecordsArchiveKeyPrefix = []byte("delegation-records-archive") + UnbondingRecordsKeyPrefix = []byte("unbonding-records-active") + UnbondingRecordsArchiveKeyPrefix = []byte("unbonding-records-archive") + RedemptionRecordsKeyPrefix = []byte("redemption-records") + SlashRecordsKeyPrefix = []byte("slash-records") + SlashRecordStoreKeyPrefix = []byte("slash-record-id") + TransferInProgressRecordIdKeyPrefix = []byte("transfer-in-progress") + + ChannelIdBufferFixedLength int = 16 +) + +// Serializes an string to use as a prefix when needed +func StringKey(p string) []byte { + return []byte(p) +} + +// Serializes an int to use as a prefix when needed +func IntKey(i uint64) []byte { + bz := make([]byte, 8) + binary.BigEndian.PutUint64(bz, i) + return bz +} + +// Builds the redemption record key from an unbonding record ID and address +func RedemptionRecordKey(unbondingRecordId uint64, redeemerAddress string) []byte { + return append(IntKey(unbondingRecordId), StringKey(redeemerAddress)...) +} + +// Builds the transfer-in-progress record key from the channelId and sequence number +func TransferInProgressRecordKey(channelId string, sequence uint64) []byte { + channelIdBz := make([]byte, ChannelIdBufferFixedLength) + copy(channelIdBz[:], channelId) + return append(channelIdBz, IntKey(sequence)...) +} diff --git a/x/stakedym/types/msgs.go b/x/stakedym/types/msgs.go new file mode 100644 index 0000000000..aebc01fae6 --- /dev/null +++ b/x/stakedym/types/msgs.go @@ -0,0 +1,676 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + + "github.com/Stride-Labs/stride/v18/utils" +) + +const ( + TypeMsgLiquidStake = "liquid_stake" + TypeMsgRedeemStake = "redeem_stake" + TypeMsgConfirmDelegation = "confirm_delegation" + TypeMsgConfirmUndelegation = "confirm_undelegation" + TypeMsgConfirmUnbondedTokenSweep = "confirm_unbonded_token_sweep" + TypeMsgAdjustDelegatedBalance = "adjust_delegated_balance" + TypeMsgUpdateInnerRedemptionRateBounds = "redemption_rate_bounds" + TypeMsgResumeHostZone = "resume_host_zone" + TypeMsgRefreshRedemptionRate = "refresh_redemption_rate" + TypeMsgOverwriteDelegationRecord = "overwrite_delegation_record" + TypeMsgOverwriteUnbondingRecord = "overwrite_unbonding_record" + TypeMsgOverwriteRedemptionRecord = "overwrite_redemption_record" + TypeMsgSetOperatorAddress = "set_operator_address" +) + +var ( + _ sdk.Msg = &MsgLiquidStake{} + _ sdk.Msg = &MsgRedeemStake{} + _ sdk.Msg = &MsgConfirmDelegation{} + _ sdk.Msg = &MsgConfirmUndelegation{} + _ sdk.Msg = &MsgConfirmUnbondedTokenSweep{} + _ sdk.Msg = &MsgAdjustDelegatedBalance{} + _ sdk.Msg = &MsgUpdateInnerRedemptionRateBounds{} + _ sdk.Msg = &MsgResumeHostZone{} + _ sdk.Msg = &MsgRefreshRedemptionRate{} + _ sdk.Msg = &MsgOverwriteDelegationRecord{} + _ sdk.Msg = &MsgOverwriteUnbondingRecord{} + _ sdk.Msg = &MsgOverwriteRedemptionRecord{} + _ sdk.Msg = &MsgSetOperatorAddress{} + + // Implement legacy interface for ledger support + _ legacytx.LegacyMsg = &MsgLiquidStake{} + _ legacytx.LegacyMsg = &MsgRedeemStake{} + _ legacytx.LegacyMsg = &MsgConfirmDelegation{} + _ legacytx.LegacyMsg = &MsgConfirmUndelegation{} + _ legacytx.LegacyMsg = &MsgConfirmUnbondedTokenSweep{} + _ legacytx.LegacyMsg = &MsgAdjustDelegatedBalance{} + _ legacytx.LegacyMsg = &MsgUpdateInnerRedemptionRateBounds{} + _ legacytx.LegacyMsg = &MsgResumeHostZone{} + _ legacytx.LegacyMsg = &MsgRefreshRedemptionRate{} + _ legacytx.LegacyMsg = &MsgOverwriteDelegationRecord{} + _ legacytx.LegacyMsg = &MsgOverwriteUnbondingRecord{} + _ legacytx.LegacyMsg = &MsgOverwriteRedemptionRecord{} + _ legacytx.LegacyMsg = &MsgSetOperatorAddress{} +) + +// ---------------------------------------------- +// MsgLiquidStake +// ---------------------------------------------- + +func NewMsgLiquidStake(staker string, nativeAmount sdkmath.Int) *MsgLiquidStake { + return &MsgLiquidStake{ + Staker: staker, + NativeAmount: nativeAmount, + } +} + +func (msg MsgLiquidStake) Type() string { + return TypeMsgLiquidStake +} + +func (msg MsgLiquidStake) Route() string { + return RouterKey +} + +func (msg *MsgLiquidStake) GetSigners() []sdk.AccAddress { + staker, err := sdk.AccAddressFromBech32(msg.Staker) + if err != nil { + panic(err) + } + return []sdk.AccAddress{staker} +} + +func (msg *MsgLiquidStake) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgLiquidStake) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Staker) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", err) + } + // threshold of 0.1 DYM or 1e17 adym avoids denial of service or record spamming + // minThreshold := int64(100_000_000_000_000_000) + minThreshold := int64(100_000) + if msg.NativeAmount.LT(sdkmath.NewInt(minThreshold)) { + return errorsmod.Wrapf(ErrInvalidAmountBelowMinimum, "amount (%v) is below 0.1 DYM minimum", msg.NativeAmount) + } + return nil +} + +// ---------------------------------------------- +// MsgRedeemStake +// ---------------------------------------------- + +func NewMsgRedeemStake(redeemer string, stTokenAmount sdkmath.Int) *MsgRedeemStake { + return &MsgRedeemStake{ + Redeemer: redeemer, + StTokenAmount: stTokenAmount, + } +} + +func (msg MsgRedeemStake) Type() string { + return TypeMsgRedeemStake +} + +func (msg MsgRedeemStake) Route() string { + return RouterKey +} + +func (msg *MsgRedeemStake) GetSigners() []sdk.AccAddress { + redeemer, err := sdk.AccAddressFromBech32(msg.Redeemer) + if err != nil { + panic(err) + } + return []sdk.AccAddress{redeemer} +} + +func (msg *MsgRedeemStake) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgRedeemStake) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Redeemer) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", msg.Redeemer) + } + // threshold of 0.1 stDYM or 100000 stadym avoids denial of service or record spamming + minThreshold := int64(100000) + if msg.StTokenAmount.LT(sdkmath.NewInt(minThreshold)) { + return errorsmod.Wrapf(ErrInvalidAmountBelowMinimum, "amount (%v) is below 0.1 stDYM minimum", msg.StTokenAmount) + } + + return nil +} + +// ---------------------------------------------- +// MsgConfirmDelegation +// ---------------------------------------------- + +func NewMsgConfirmDelegation(operator string, recordId uint64, txHash string) *MsgConfirmDelegation { + return &MsgConfirmDelegation{ + Operator: operator, + RecordId: recordId, + TxHash: txHash, + } +} + +func (msg MsgConfirmDelegation) Type() string { + return TypeMsgConfirmDelegation +} + +func (msg MsgConfirmDelegation) Route() string { + return RouterKey +} + +func (msg *MsgConfirmDelegation) GetSigners() []sdk.AccAddress { + operator, err := sdk.AccAddressFromBech32(msg.Operator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{operator} +} + +func (msg *MsgConfirmDelegation) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgConfirmDelegation) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Operator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", err) + } + // Note: We can't verify admin in ValidateBasic, because it requires inspecting the HostZone + // Note: We can't verify recordId in ValidateBasic, because 0 is a valid record id + // and recordId is uint64 so can't be negative + if err := utils.VerifyTxHash(msg.TxHash); err != nil { + return err + } + return nil +} + +// ---------------------------------------------- +// MsgConfirmUndelegation +// ---------------------------------------------- + +func NewMsgConfirmUndelegation(operator string, recordId uint64, txHash string) *MsgConfirmUndelegation { + return &MsgConfirmUndelegation{ + Operator: operator, + RecordId: recordId, + TxHash: txHash, + } +} + +func (msg MsgConfirmUndelegation) Type() string { + return TypeMsgConfirmUndelegation +} + +func (msg MsgConfirmUndelegation) Route() string { + return RouterKey +} + +func (msg *MsgConfirmUndelegation) GetSigners() []sdk.AccAddress { + operator, err := sdk.AccAddressFromBech32(msg.Operator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{operator} +} + +func (msg *MsgConfirmUndelegation) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgConfirmUndelegation) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Operator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", err) + } + // verify tx hash is valid + if err := utils.VerifyTxHash(msg.TxHash); err != nil { + return err + } + + return nil +} + +// ---------------------------------------------- +// MsgConfirmUnbondedTokenSweep +// ---------------------------------------------- + +func NewMsgConfirmUnbondedTokenSweep(operator string, recordId uint64, txHash string) *MsgConfirmUnbondedTokenSweep { + return &MsgConfirmUnbondedTokenSweep{ + Operator: operator, + RecordId: recordId, + TxHash: txHash, + } +} + +func (msg MsgConfirmUnbondedTokenSweep) Type() string { + return TypeMsgConfirmUnbondedTokenSweep +} + +func (msg MsgConfirmUnbondedTokenSweep) Route() string { + return RouterKey +} + +func (msg *MsgConfirmUnbondedTokenSweep) GetSigners() []sdk.AccAddress { + operator, err := sdk.AccAddressFromBech32(msg.Operator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{operator} +} + +func (msg *MsgConfirmUnbondedTokenSweep) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgConfirmUnbondedTokenSweep) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Operator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", err) + } + // Note: We can't verify this is sent by the safe or operator in ValidateBasic, because it requires inspecting the HostZone + // Note: We can't verify recordId in ValidateBasic, because 0 is a valid record id + // and recordId is uint64 so can't be negative + if err := utils.VerifyTxHash(msg.TxHash); err != nil { + return err + } + return nil +} + +// ---------------------------------------------- +// MsgAdjustDelegatedBalance +// ---------------------------------------------- + +func NewMsgAdjustDelegatedBalance(operator string, delegationOffset sdkmath.Int, validatorAddress string) *MsgAdjustDelegatedBalance { + return &MsgAdjustDelegatedBalance{ + Operator: operator, + DelegationOffset: delegationOffset, + ValidatorAddress: validatorAddress, + } +} + +func (msg MsgAdjustDelegatedBalance) Type() string { + return TypeMsgAdjustDelegatedBalance +} + +func (msg MsgAdjustDelegatedBalance) Route() string { + return RouterKey +} + +func (msg *MsgAdjustDelegatedBalance) GetSigners() []sdk.AccAddress { + operator, err := sdk.AccAddressFromBech32(msg.Operator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{operator} +} + +func (msg *MsgAdjustDelegatedBalance) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgAdjustDelegatedBalance) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Operator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", err) + } + if msg.DelegationOffset.IsNil() { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "delegation offset must be specified") + } + if msg.ValidatorAddress == "" { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "validator address must be specified") + } + return nil +} + +// ---------------------------------------------- +// MsgUpdateInnerRedemptionRateBounds +// ---------------------------------------------- + +func NewMsgUpdateInnerRedemptionRateBounds(creator string, minRedemptionRate, maxRedemptionRate sdk.Dec) *MsgUpdateInnerRedemptionRateBounds { + return &MsgUpdateInnerRedemptionRateBounds{ + Creator: creator, + MinInnerRedemptionRate: minRedemptionRate, + MaxInnerRedemptionRate: maxRedemptionRate, + } +} + +func (msg MsgUpdateInnerRedemptionRateBounds) Type() string { + return TypeMsgUpdateInnerRedemptionRateBounds +} + +func (msg MsgUpdateInnerRedemptionRateBounds) Route() string { + return RouterKey +} + +func (msg *MsgUpdateInnerRedemptionRateBounds) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgUpdateInnerRedemptionRateBounds) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgUpdateInnerRedemptionRateBounds) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", err) + } + // Confirm the max is greater than the min + if msg.MaxInnerRedemptionRate.LTE(msg.MinInnerRedemptionRate) { + return errorsmod.Wrapf(ErrInvalidRedemptionRateBounds, + "Inner max safety threshold (%s) is less than inner min safety threshold (%s)", + msg.MaxInnerRedemptionRate, msg.MinInnerRedemptionRate) + } + if err := utils.ValidateAdminAddress(msg.Creator); err != nil { + return err + } + return nil +} + +// ---------------------------------------------- +// MsgResumeHostZone +// ---------------------------------------------- + +func NewMsgResumeHostZone(creator string) *MsgResumeHostZone { + return &MsgResumeHostZone{ + Creator: creator, + } +} + +func (msg MsgResumeHostZone) Type() string { + return TypeMsgResumeHostZone +} + +func (msg MsgResumeHostZone) Route() string { + return RouterKey +} + +func (msg *MsgResumeHostZone) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgResumeHostZone) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgResumeHostZone) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", err) + } + if err := utils.ValidateAdminAddress(msg.Creator); err != nil { + return err + } + return nil +} + +// ---------------------------------------------- +// MsgSetOperatorAddress +// ---------------------------------------------- + +func NewMsgSetOperatorAddress(signer string, operator string) *MsgSetOperatorAddress { + return &MsgSetOperatorAddress{ + Signer: signer, + Operator: operator, + } +} + +func (msg MsgSetOperatorAddress) Type() string { + return TypeMsgSetOperatorAddress +} + +func (msg MsgSetOperatorAddress) Route() string { + return RouterKey +} + +func (msg *MsgSetOperatorAddress) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgSetOperatorAddress) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgSetOperatorAddress) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid signer address (%s)", err) + } + _, err = sdk.AccAddressFromBech32(msg.Operator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid operator address (%s)", err) + } + return nil +} + +// ---------------------------------------------- +// MsgRefreshRedemptionRate +// ---------------------------------------------- + +func NewMsgRefreshRedemptionRate(creator string) *MsgRefreshRedemptionRate { + return &MsgRefreshRedemptionRate{ + Creator: creator, + } +} + +func (msg MsgRefreshRedemptionRate) Type() string { + return TypeMsgRefreshRedemptionRate +} + +func (msg MsgRefreshRedemptionRate) Route() string { + return RouterKey +} + +func (msg *MsgRefreshRedemptionRate) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgRefreshRedemptionRate) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgRefreshRedemptionRate) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", err) + } + return nil +} + +// ---------------------------------------------- +// MsgOverwriteDelegationRecord +// ---------------------------------------------- + +func NewMsgOverwriteDelegationRecord(creator string, delegationRecord DelegationRecord) *MsgOverwriteDelegationRecord { + return &MsgOverwriteDelegationRecord{ + Creator: creator, + DelegationRecord: &delegationRecord, + } +} + +func (msg MsgOverwriteDelegationRecord) Type() string { + return TypeMsgOverwriteDelegationRecord +} + +func (msg MsgOverwriteDelegationRecord) Route() string { + return RouterKey +} + +func (msg *MsgOverwriteDelegationRecord) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgOverwriteDelegationRecord) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgOverwriteDelegationRecord) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", err) + } + + // Check the record's attributes + // - assert the nativeAmount is non-negative (zero is acceptable) + if msg.DelegationRecord.NativeAmount.LT(sdk.ZeroInt()) { + return errorsmod.Wrapf(ErrInvalidAmountBelowMinimum, "amount < 0") + } + + // - assert the status is one of the acceptable statuses + if _, ok := DelegationRecordStatus_name[int32(msg.DelegationRecord.Status)]; !ok { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "record status doesn't match the enum") + } + + return nil +} + +// ---------------------------------------------- +// MsgOverwriteUnbondingRecord +// ---------------------------------------------- + +func NewMsgOverwriteUnbondingRecord(creator string, unbondingRecord UnbondingRecord) *MsgOverwriteUnbondingRecord { + return &MsgOverwriteUnbondingRecord{ + Creator: creator, + UnbondingRecord: &unbondingRecord, + } +} + +func (msg MsgOverwriteUnbondingRecord) Type() string { + return TypeMsgOverwriteUnbondingRecord +} + +func (msg MsgOverwriteUnbondingRecord) Route() string { + return RouterKey +} + +func (msg *MsgOverwriteUnbondingRecord) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgOverwriteUnbondingRecord) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgOverwriteUnbondingRecord) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", err) + } + + // Check the record's attributes + // - assert the nativeAmount is non-negative (zero is acceptable) + if msg.UnbondingRecord.NativeAmount.LT(sdk.ZeroInt()) { + return errorsmod.Wrapf(ErrInvalidAmountBelowMinimum, "native amount < 0") + } + // - assert the stTokenAmount is non-negative (zero is acceptable) + if msg.UnbondingRecord.StTokenAmount.LT(sdk.ZeroInt()) { + return errorsmod.Wrapf(ErrInvalidAmountBelowMinimum, "sttoken amount < 0") + } + + // - assert the status is one of the acceptable statuses + if _, ok := UnbondingRecordStatus_name[int32(msg.UnbondingRecord.Status)]; !ok { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "record status doesn't match the enum") + } + + return nil +} + +// ---------------------------------------------- +// MsgOverwriteRedemptionRecord +// ---------------------------------------------- + +func NewMsgOverwriteRedemptionRecord(creator string, redemptionRecord RedemptionRecord) *MsgOverwriteRedemptionRecord { + return &MsgOverwriteRedemptionRecord{ + Creator: creator, + RedemptionRecord: &redemptionRecord, + } +} + +func (msg MsgOverwriteRedemptionRecord) Type() string { + return TypeMsgOverwriteRedemptionRecord +} + +func (msg MsgOverwriteRedemptionRecord) Route() string { + return RouterKey +} + +func (msg *MsgOverwriteRedemptionRecord) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgOverwriteRedemptionRecord) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgOverwriteRedemptionRecord) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", err) + } + + // Check the record's attributes + // - assert the redeemer is a valid address + _, err = sdk.AccAddressFromBech32(msg.RedemptionRecord.Redeemer) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid address (%s)", err) + } + // - assert the nativeAmount is non-negative (zero is acceptable) + if msg.RedemptionRecord.NativeAmount.LT(sdk.ZeroInt()) { + return errorsmod.Wrapf(ErrInvalidAmountBelowMinimum, "amount < 0") + } + // - assert the stTokenAmount is non-negative (zero is acceptable) + if msg.RedemptionRecord.StTokenAmount.LT(sdk.ZeroInt()) { + return errorsmod.Wrapf(ErrInvalidAmountBelowMinimum, "amount < 0") + } + + return nil +} diff --git a/x/stakedym/types/msgs_test.go b/x/stakedym/types/msgs_test.go new file mode 100644 index 0000000000..62efe8bc22 --- /dev/null +++ b/x/stakedym/types/msgs_test.go @@ -0,0 +1,950 @@ +package types_test + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/require" + + "github.com/Stride-Labs/stride/v18/app/apptesting" + "github.com/Stride-Labs/stride/v18/testutil/sample" + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +// ---------------------------------------------- +// MsgLiquidStake +// ---------------------------------------------- + +func TestMsgLiquidStake_ValidateBasic(t *testing.T) { + tests := []struct { + name string + msg types.MsgLiquidStake + err error + }{ + { + name: "invalid address", + msg: types.MsgLiquidStake{ + Staker: "invalid_address", + NativeAmount: sdkmath.NewInt(1000000), + }, + err: sdkerrors.ErrInvalidAddress, + }, + { + name: "invalid address: wrong chain's bech32prefix", + msg: types.MsgLiquidStake{ + Staker: "tia1yjq0n2ewufluenyyvj2y9sead9jfstpxnqv2xz", + NativeAmount: sdkmath.NewInt(1000000), + }, + err: sdkerrors.ErrInvalidAddress, + }, + { + name: "valid inputs", + msg: types.MsgLiquidStake{ + Staker: sample.AccAddress(), + NativeAmount: sdkmath.NewInt(1200000), + }, + }, + { + name: "amount below threshold", + msg: types.MsgLiquidStake{ + Staker: sample.AccAddress(), + NativeAmount: sdkmath.NewInt(20000), + }, + err: types.ErrInvalidAmountBelowMinimum, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // check validatebasic() + err := tt.msg.ValidateBasic() + if tt.err != nil { + require.ErrorIs(t, err, tt.err) + return + } + require.NoError(t, err) + }) + } +} + +func TestMsgLiquidStake_GetSignBytes(t *testing.T) { + addr := "stride1v9jxgu33kfsgr5" + msg := types.NewMsgLiquidStake(addr, sdkmath.NewInt(1000)) + res := msg.GetSignBytes() + + expected := `{"type":"stakedym/MsgLiquidStake","value":{"native_amount":"1000","staker":"stride1v9jxgu33kfsgr5"}}` + require.Equal(t, expected, string(res)) +} + +// ---------------------------------------------- +// MsgRedeemStake +// ---------------------------------------------- + +func TestMsgRedeemStake_ValidateBasic(t *testing.T) { + tests := []struct { + name string + msg types.MsgRedeemStake + err error + }{ + { + name: "success", + msg: types.MsgRedeemStake{ + Redeemer: sample.AccAddress(), + StTokenAmount: sdkmath.NewInt(1000000), + }, + }, + { + name: "invalid creator", + msg: types.MsgRedeemStake{ + Redeemer: "invalid_address", + StTokenAmount: sdkmath.NewInt(1000000), + }, + err: sdkerrors.ErrInvalidAddress, + }, + { + name: "amount below threshold", + msg: types.MsgRedeemStake{ + Redeemer: sample.AccAddress(), + StTokenAmount: sdkmath.NewInt(20000), + }, + err: types.ErrInvalidAmountBelowMinimum, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.msg.ValidateBasic() + if tt.err != nil { + require.ErrorIs(t, err, tt.err) + return + } + require.NoError(t, err) + }) + } +} + +func TestMsgRedeemStake_GetSignBytes(t *testing.T) { + addr := "stride1v9jxgu33kfsgr5" + msg := types.NewMsgRedeemStake(addr, sdkmath.NewInt(1000000)) + res := msg.GetSignBytes() + + expected := `{"type":"stakedym/MsgRedeemStake","value":{"redeemer":"stride1v9jxgu33kfsgr5","st_token_amount":"1000000"}}` + require.Equal(t, expected, string(res)) +} + +// ---------------------------------------------- +// MsgConfirmDelegation +// ---------------------------------------------- + +func TestMsgConfirmDelegation_ValidateBasic(t *testing.T) { + validTxHash := "BBD978ADDBF580AC2981E351A3EA34AA9D7B57631E9CE21C27C2C63A5B13BDA9" + validRecordId := uint64(35) + validAddress := sample.AccAddress() + + tests := []struct { + name string + msg types.MsgConfirmDelegation + expectedError string + }{ + { + name: "success", + msg: types.MsgConfirmDelegation{ + Operator: validAddress, + RecordId: validRecordId, + TxHash: validTxHash, + }, + }, + { + name: "empty tx hash", + msg: types.MsgConfirmDelegation{ + Operator: validAddress, + RecordId: validRecordId, + TxHash: "", + }, + expectedError: "tx hash is empty", + }, + { + name: "invalid tx hash", + msg: types.MsgConfirmDelegation{ + Operator: validAddress, + RecordId: validRecordId, + TxHash: "invalid_tx-hash", + }, + expectedError: "tx hash is invalid", + }, + { + name: "invalid sender", + msg: types.MsgConfirmDelegation{ + Operator: "strideinvalid", + RecordId: validRecordId, + TxHash: validTxHash, + }, + expectedError: "invalid address", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.msg.ValidateBasic() + if tt.expectedError == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tt.expectedError) + } + }) + } +} + +func TestMsgConfirmDelegation_GetSignBytes(t *testing.T) { + addr := "stride1v9jxgu33kfsgr5" + msg := types.NewMsgConfirmDelegation(addr, 100, "valid_hash") + res := msg.GetSignBytes() + + expected := `{"type":"stakedym/MsgConfirmDelegation","value":{"operator":"stride1v9jxgu33kfsgr5","record_id":"100","tx_hash":"valid_hash"}}` + require.Equal(t, expected, string(res)) +} + +// ---------------------------------------------- +// MsgConfirmUndelegation +// ---------------------------------------------- + +func TestMsgConfirmUndelegation_ValidateBasic(t *testing.T) { + validTxHash := "BBD978ADDBF580AC2981E351A3EA34AA9D7B57631E9CE21C27C2C63A5B13BDA9" + validRecordId := uint64(35) + validAddress := sample.AccAddress() + + tests := []struct { + name string + msg types.MsgConfirmUndelegation + expectedError string + }{ + { + name: "success", + msg: types.MsgConfirmUndelegation{ + Operator: validAddress, + RecordId: validRecordId, + TxHash: validTxHash, + }, + }, + { + name: "empty tx hash", + msg: types.MsgConfirmUndelegation{ + Operator: validAddress, + RecordId: validRecordId, + TxHash: "", + }, + expectedError: "tx hash is empty", + }, + { + name: "invalid tx hash", + msg: types.MsgConfirmUndelegation{ + Operator: validAddress, + RecordId: validRecordId, + TxHash: "invalid_tx-hash", + }, + expectedError: "tx hash is invalid", + }, + { + name: "invalid sender", + msg: types.MsgConfirmUndelegation{ + Operator: "strideinvalid", + RecordId: validRecordId, + TxHash: validTxHash, + }, + expectedError: "invalid address", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.msg.ValidateBasic() + if tt.expectedError == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tt.expectedError) + } + }) + } +} + +func TestMsgConfirmUndelegation_GetSignBytes(t *testing.T) { + addr := "stride1v9jxgu33kfsgr5" + msg := types.NewMsgConfirmUndelegation(addr, 100, "valid_hash") + res := msg.GetSignBytes() + + expected := `{"type":"stakedym/MsgConfirmUndelegation","value":{"operator":"stride1v9jxgu33kfsgr5","record_id":"100","tx_hash":"valid_hash"}}` + require.Equal(t, expected, string(res)) +} + +// ---------------------------------------------- +// MsgConfirmUnbondedTokenSweep +// ---------------------------------------------- + +func TestMsgConfirmUnbondedTokenSweep_ValidateBasic(t *testing.T) { + tests := []struct { + name string + msg types.MsgConfirmUnbondedTokenSweep + err error + }{ + { + name: "success", + msg: types.MsgConfirmUnbondedTokenSweep{ + Operator: sample.AccAddress(), + RecordId: 35, + TxHash: "BBD978ADDBF580AC2981E351A3EA34AA9D7B57631E9CE21C27C2C63A5B13BDA9", + }, + }, + { + name: "empty tx hash", + msg: types.MsgConfirmUnbondedTokenSweep{ + Operator: sample.AccAddress(), + RecordId: 35, + TxHash: "", + }, + err: sdkerrors.ErrTxDecode, + }, + { + name: "invalid tx hash", + msg: types.MsgConfirmUnbondedTokenSweep{ + Operator: sample.AccAddress(), + RecordId: 35, + TxHash: "invalid_tx-hash", + }, + err: sdkerrors.ErrTxDecode, + }, + { + name: "invalid sender", + msg: types.MsgConfirmUnbondedTokenSweep{ + Operator: "strideinvalid", + RecordId: 35, + TxHash: "BBD978ADDBF580AC2981E351A3EA34AA9D7B57631E9CE21C27C2C63A5B13BDA9", + }, + err: sdkerrors.ErrInvalidAddress, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.msg.ValidateBasic() + if tt.err != nil { + require.ErrorIs(t, err, tt.err) + return + } + require.NoError(t, err) + }) + } +} + +func TestMsgConfirmUnbondedTokenSweep_GetSignBytes(t *testing.T) { + addr := "stride1v9jxgu33kfsgr5" + msg := types.NewMsgConfirmUnbondedTokenSweep(addr, 100, "valid_hash") + res := msg.GetSignBytes() + + expected := `{"type":"stakedym/MsgConfirmUnbondedTokenSweep","value":{"operator":"stride1v9jxgu33kfsgr5","record_id":"100","tx_hash":"valid_hash"}}` + require.Equal(t, expected, string(res)) +} + +// ---------------------------------------------- +// MsgAdjustDelegatedBalance +// ---------------------------------------------- + +func TestMsgAdjustDelegatedBalance_ValidateBasic(t *testing.T) { + apptesting.SetupConfig() + + validAddress, invalidAddress := apptesting.GenerateTestAddrs() + validValidatorAddress := "valoper" + validDelegationOffset := sdkmath.NewInt(10) + + tests := []struct { + name string + msg types.MsgAdjustDelegatedBalance + err string + }{ + { + name: "successful message", + msg: types.MsgAdjustDelegatedBalance{ + Operator: validAddress, + DelegationOffset: validDelegationOffset, + ValidatorAddress: validValidatorAddress, + }, + }, + { + name: "successful message, negative offset", + msg: types.MsgAdjustDelegatedBalance{ + Operator: validAddress, + DelegationOffset: sdkmath.NewInt(-1), + ValidatorAddress: validValidatorAddress, + }, + }, + { + name: "invalid signer address", + msg: types.MsgAdjustDelegatedBalance{ + Operator: invalidAddress, + DelegationOffset: validDelegationOffset, + ValidatorAddress: validValidatorAddress, + }, + err: "invalid address", + }, + { + name: "invalid delegation offset", + msg: types.MsgAdjustDelegatedBalance{ + Operator: validAddress, + ValidatorAddress: validValidatorAddress, + }, + err: "delegation offset must be specified", + }, + { + name: "invalid validator address", + msg: types.MsgAdjustDelegatedBalance{ + Operator: validAddress, + DelegationOffset: validDelegationOffset, + ValidatorAddress: "", + }, + err: "validator address must be specified", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.err == "" { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + + signers := test.msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), validAddress) + + require.Equal(t, test.msg.Type(), "adjust_delegated_balance", "type") + } else { + require.ErrorContains(t, test.msg.ValidateBasic(), test.err, "test: %v", test.name) + } + }) + } +} + +// ---------------------------------------------- +// MsgUpdateInnerRedemptionRateBounds +// ---------------------------------------------- + +func TestMsgUpdateInnerRedemptionRateBounds_ValidateBasic(t *testing.T) { + apptesting.SetupConfig() + + validNotAdminAddress, invalidAddress := apptesting.GenerateTestAddrs() + validAdminAddress, ok := apptesting.GetAdminAddress() + require.True(t, ok) + + validUpperBound := sdk.NewDec(2) + validLowerBound := sdk.NewDec(1) + invalidLowerBound := sdk.NewDec(2) + + tests := []struct { + name string + msg types.MsgUpdateInnerRedemptionRateBounds + err string + }{ + { + name: "successful message", + msg: types.MsgUpdateInnerRedemptionRateBounds{ + Creator: validAdminAddress, + MaxInnerRedemptionRate: validUpperBound, + MinInnerRedemptionRate: validLowerBound, + }, + }, + { + name: "invalid creator address", + msg: types.MsgUpdateInnerRedemptionRateBounds{ + Creator: invalidAddress, + MaxInnerRedemptionRate: validUpperBound, + MinInnerRedemptionRate: validLowerBound, + }, + err: "invalid address", + }, + { + name: "invalid admin address", + msg: types.MsgUpdateInnerRedemptionRateBounds{ + Creator: validNotAdminAddress, + MaxInnerRedemptionRate: validUpperBound, + MinInnerRedemptionRate: validLowerBound, + }, + err: "not an admin: invalid address", + }, + { + name: "invalid bounds", + msg: types.MsgUpdateInnerRedemptionRateBounds{ + Creator: validAdminAddress, + MaxInnerRedemptionRate: validUpperBound, + MinInnerRedemptionRate: invalidLowerBound, + }, + err: "invalid host zone redemption rate inner bounds", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.err == "" { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + + signers := test.msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), validAdminAddress) + + require.Equal(t, test.msg.MaxInnerRedemptionRate, validUpperBound, "MaxInnerRedemptionRate") + require.Equal(t, test.msg.MinInnerRedemptionRate, validLowerBound, "MaxInnerRedemptionRate") + require.Equal(t, test.msg.Type(), "redemption_rate_bounds", "type") + } else { + require.ErrorContains(t, test.msg.ValidateBasic(), test.err, "test: %v", test.name) + } + }) + } +} + +// ---------------------------------------------- +// MsgResumeHostZone +// ---------------------------------------------- + +func TestMsgResumeHostZone_ValidateBasic(t *testing.T) { + apptesting.SetupConfig() + + validNotAdminAddress, invalidAddress := apptesting.GenerateTestAddrs() + validAdminAddress, ok := apptesting.GetAdminAddress() + require.True(t, ok) + + tests := []struct { + name string + msg types.MsgResumeHostZone + err string + }{ + { + name: "successful message", + msg: types.MsgResumeHostZone{ + Creator: validAdminAddress, + }, + }, + { + name: "invalid creator address", + msg: types.MsgResumeHostZone{ + Creator: invalidAddress, + }, + err: "invalid address", + }, + { + name: "invalid admin address", + msg: types.MsgResumeHostZone{ + Creator: validNotAdminAddress, + }, + err: "not an admin: invalid address", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.err == "" { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + + signers := test.msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), validAdminAddress) + + require.Equal(t, test.msg.Type(), "resume_host_zone", "type") + } else { + require.ErrorContains(t, test.msg.ValidateBasic(), test.err, "test: %v", test.name) + } + }) + } +} + +// ---------------------------------------------- +// MsgRefreshRedemptionRate +// ---------------------------------------------- + +func TestMsgRefreshRedemptionRate_ValidateBasic(t *testing.T) { + apptesting.SetupConfig() + + validAddress, invalidAddress := apptesting.GenerateTestAddrs() + + tests := []struct { + name string + msg types.MsgRefreshRedemptionRate + err string + }{ + { + name: "successful message", + msg: types.MsgRefreshRedemptionRate{ + Creator: validAddress, + }, + }, + { + name: "invalid signer address", + msg: types.MsgRefreshRedemptionRate{ + Creator: invalidAddress, + }, + err: "invalid address", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.err == "" { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + + signers := test.msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), validAddress) + + require.Equal(t, test.msg.Type(), "refresh_redemption_rate", "type") + } else { + require.ErrorContains(t, test.msg.ValidateBasic(), test.err, "test: %v", test.name) + } + }) + } +} + +// ---------------------------------------------- +// OverwriteDelegationRecord +// ---------------------------------------------- + +func TestMsgOverwriteDelegationRecord_ValidateBasic(t *testing.T) { + apptesting.SetupConfig() + + validTxHash := "69650DCD2D68BBC9310BA4B980187483BFC81452EC99C39DA45633F077157911" + validAddress, invalidAddress := apptesting.GenerateTestAddrs() + + tests := []struct { + name string + msg types.MsgOverwriteDelegationRecord + err string + }{ + { + name: "successful message", + msg: types.MsgOverwriteDelegationRecord{ + Creator: validAddress, + DelegationRecord: &types.DelegationRecord{ + Id: 1, + NativeAmount: sdkmath.NewInt(1), + Status: types.DELEGATION_QUEUE, + TxHash: validTxHash, + }, + }, + }, + { + name: "successful message with blank tx hash", + msg: types.MsgOverwriteDelegationRecord{ + Creator: validAddress, + DelegationRecord: &types.DelegationRecord{ + Id: 1, + NativeAmount: sdkmath.NewInt(1), + Status: types.DELEGATION_QUEUE, + TxHash: "", + }, + }, + }, + { + name: "invalid signer address", + msg: types.MsgOverwriteDelegationRecord{ + Creator: invalidAddress, + DelegationRecord: &types.DelegationRecord{ + Id: 1, + NativeAmount: sdkmath.NewInt(1), + Status: types.DELEGATION_QUEUE, + TxHash: validTxHash, + }, + }, + err: "invalid address", + }, + { + name: "invalid native amount", + msg: types.MsgOverwriteDelegationRecord{ + Creator: validAddress, + DelegationRecord: &types.DelegationRecord{ + Id: 1, + NativeAmount: sdkmath.NewInt(-1), + Status: types.DELEGATION_QUEUE, + TxHash: validTxHash, + }, + }, + err: "amount < 0", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.err == "" { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + + signers := test.msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), validAddress) + + require.Equal(t, test.msg.Type(), "overwrite_delegation_record", "type") + } else { + require.ErrorContains(t, test.msg.ValidateBasic(), test.err, "test: %v", test.name) + } + }) + } +} + +// ---------------------------------------------- +// OverwriteUnbondingRecord +// ---------------------------------------------- + +func TestMsgOverwriteUnbondingRecord_ValidateBasic(t *testing.T) { + apptesting.SetupConfig() + + validTxHash1 := "69650DCD2D68BBC9310BA4B980187483BFC81452EC99C39DA45633F077157911" + validTxHash2 := "2B1B1D6C4975E1CE562DBF6C2C4D6BEF543A71D6036A0664C9B4EE2C108E6AF8" + validAddress, invalidAddress := apptesting.GenerateTestAddrs() + + tests := []struct { + name string + msg types.MsgOverwriteUnbondingRecord + err string + }{ + { + name: "successful message", + msg: types.MsgOverwriteUnbondingRecord{ + Creator: validAddress, + UnbondingRecord: &types.UnbondingRecord{ + Id: 1, + Status: types.UNBONDED, + StTokenAmount: sdkmath.NewInt(11), + NativeAmount: sdkmath.NewInt(10), + UnbondingCompletionTimeSeconds: 1705857114, // unixtime (1/21/24) + UndelegationTxHash: validTxHash1, + UnbondedTokenSweepTxHash: validTxHash2, + }, + }, + }, + { + name: "successful message with blank tx hashes", + msg: types.MsgOverwriteUnbondingRecord{ + Creator: validAddress, + UnbondingRecord: &types.UnbondingRecord{ + Id: 1, + Status: types.UNBONDED, + StTokenAmount: sdkmath.NewInt(11), + NativeAmount: sdkmath.NewInt(10), + UnbondingCompletionTimeSeconds: 1705857114, // unixtime (1/21/24) + UndelegationTxHash: "", + UnbondedTokenSweepTxHash: "", + }, + }, + }, + + { + name: "invalid signer address", + msg: types.MsgOverwriteUnbondingRecord{ + Creator: invalidAddress, // invalid + UnbondingRecord: &types.UnbondingRecord{ + Id: 1, + Status: types.UNBONDED, + StTokenAmount: sdkmath.NewInt(11), + NativeAmount: sdkmath.NewInt(10), + UnbondingCompletionTimeSeconds: 1705857114, + UndelegationTxHash: validTxHash1, + UnbondedTokenSweepTxHash: validTxHash2, + }, + }, + err: "invalid address", + }, + { + name: "invalid native amount", + msg: types.MsgOverwriteUnbondingRecord{ + Creator: validAddress, + UnbondingRecord: &types.UnbondingRecord{ + Id: 1, + Status: types.UNBONDED, + StTokenAmount: sdkmath.NewInt(11), + NativeAmount: sdkmath.NewInt(-1), // negative + UnbondingCompletionTimeSeconds: 1705857114, + UndelegationTxHash: validTxHash1, + UnbondedTokenSweepTxHash: validTxHash2, + }, + }, + err: "amount < 0", + }, + { + name: "invalid sttoken amount", + msg: types.MsgOverwriteUnbondingRecord{ + Creator: validAddress, + UnbondingRecord: &types.UnbondingRecord{ + Id: 1, + Status: types.UNBONDED, + StTokenAmount: sdkmath.NewInt(-1), // negative + NativeAmount: sdkmath.NewInt(10), + UnbondingCompletionTimeSeconds: 1705857114, + UndelegationTxHash: validTxHash1, + UnbondedTokenSweepTxHash: validTxHash2, + }, + }, + err: "amount < 0", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.err == "" { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + + signers := test.msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), validAddress) + + require.Equal(t, test.msg.Type(), "overwrite_unbonding_record", "type") + } else { + require.ErrorContains(t, test.msg.ValidateBasic(), test.err, "test: %v", test.name) + } + }) + } +} + +// ---------------------------------------------- +// OverwriteRedemptionRecord +// ---------------------------------------------- + +func TestMsgOverwriteRedemptionRecord_ValidateBasic(t *testing.T) { + apptesting.SetupConfig() + + validAddress, invalidAddress := apptesting.GenerateTestAddrs() + + tests := []struct { + name string + msg types.MsgOverwriteRedemptionRecord + err string + }{ + { + name: "successful message", + msg: types.MsgOverwriteRedemptionRecord{ + Creator: validAddress, + RedemptionRecord: &types.RedemptionRecord{ + UnbondingRecordId: 1, + Redeemer: validAddress, + StTokenAmount: sdkmath.NewInt(11), + NativeAmount: sdkmath.NewInt(10), + }, + }, + }, + { + name: "invalid signer address", + msg: types.MsgOverwriteRedemptionRecord{ + Creator: invalidAddress, + RedemptionRecord: &types.RedemptionRecord{ + UnbondingRecordId: 1, + Redeemer: validAddress, + StTokenAmount: sdkmath.NewInt(11), + NativeAmount: sdkmath.NewInt(10), + }, + }, + err: "invalid address", + }, + { + name: "invalid redeemer address", + msg: types.MsgOverwriteRedemptionRecord{ + Creator: validAddress, + RedemptionRecord: &types.RedemptionRecord{ + UnbondingRecordId: 1, + Redeemer: invalidAddress, + StTokenAmount: sdkmath.NewInt(11), + NativeAmount: sdkmath.NewInt(10), + }, + }, + err: "invalid address", + }, + { + name: "invalid native amount", + msg: types.MsgOverwriteRedemptionRecord{ + Creator: validAddress, + RedemptionRecord: &types.RedemptionRecord{ + UnbondingRecordId: 1, + Redeemer: validAddress, + StTokenAmount: sdkmath.NewInt(11), + NativeAmount: sdkmath.NewInt(-1), + }, + }, + err: "amount < 0", + }, + { + name: "invalid sttoken amount", + msg: types.MsgOverwriteRedemptionRecord{ + Creator: validAddress, + RedemptionRecord: &types.RedemptionRecord{ + UnbondingRecordId: 1, + Redeemer: validAddress, + StTokenAmount: sdkmath.NewInt(-1), + NativeAmount: sdkmath.NewInt(10), + }, + }, + err: "amount < 0", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.err == "" { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + + signers := test.msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), validAddress) + + require.Equal(t, test.msg.Type(), "overwrite_redemption_record", "type") + } else { + require.ErrorContains(t, test.msg.ValidateBasic(), test.err, "test: %v", test.name) + } + }) + } +} + +// ---------------------------------------------- +// MsgSetOperatorAddress +// ---------------------------------------------- + +func TestMsgSetOperatorAddress_ValidateBasic(t *testing.T) { + apptesting.SetupConfig() + + validAddress, invalidAddress := apptesting.GenerateTestAddrs() + + tests := []struct { + name string + msg types.MsgSetOperatorAddress + err string + }{ + { + name: "successful message", + msg: types.MsgSetOperatorAddress{ + Signer: validAddress, + Operator: validAddress, + }, + }, + { + name: "invalid signer address", + msg: types.MsgSetOperatorAddress{ + Signer: invalidAddress, + Operator: validAddress, + }, + err: "invalid address", + }, + { + name: "invalid operator address", + msg: types.MsgSetOperatorAddress{ + Signer: validAddress, + Operator: invalidAddress, + }, + err: "invalid address", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.err == "" { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + + signers := test.msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), validAddress) + + require.Equal(t, test.msg.Type(), "set_operator_address", "type") + } else { + require.ErrorContains(t, test.msg.ValidateBasic(), test.err, "test: %v", test.name) + } + }) + } +} diff --git a/x/stakedym/types/params.go b/x/stakedym/types/params.go new file mode 100644 index 0000000000..874012a4b8 --- /dev/null +++ b/x/stakedym/types/params.go @@ -0,0 +1,16 @@ +package types + +// NewParams creates a new Params instance +func NewParams() Params { + return Params{} +} + +// DefaultParams returns a default set of parameters +func DefaultParams() Params { + return NewParams() +} + +// Validate validates the set of params +func (p Params) Validate() error { + return nil +} diff --git a/x/stakedym/types/query.pb.go b/x/stakedym/types/query.pb.go new file mode 100644 index 0000000000..b3501a7b92 --- /dev/null +++ b/x/stakedym/types/query.pb.go @@ -0,0 +1,2882 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: stride/stakedym/query.proto + +package types + +import ( + context "context" + fmt "fmt" + query "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Host Zone +type QueryHostZoneRequest struct { +} + +func (m *QueryHostZoneRequest) Reset() { *m = QueryHostZoneRequest{} } +func (m *QueryHostZoneRequest) String() string { return proto.CompactTextString(m) } +func (*QueryHostZoneRequest) ProtoMessage() {} +func (*QueryHostZoneRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{0} +} +func (m *QueryHostZoneRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryHostZoneRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryHostZoneRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryHostZoneRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryHostZoneRequest.Merge(m, src) +} +func (m *QueryHostZoneRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryHostZoneRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryHostZoneRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryHostZoneRequest proto.InternalMessageInfo + +type QueryHostZoneResponse struct { + HostZone *HostZone `protobuf:"bytes,1,opt,name=host_zone,json=hostZone,proto3" json:"host_zone,omitempty"` +} + +func (m *QueryHostZoneResponse) Reset() { *m = QueryHostZoneResponse{} } +func (m *QueryHostZoneResponse) String() string { return proto.CompactTextString(m) } +func (*QueryHostZoneResponse) ProtoMessage() {} +func (*QueryHostZoneResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{1} +} +func (m *QueryHostZoneResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryHostZoneResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryHostZoneResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryHostZoneResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryHostZoneResponse.Merge(m, src) +} +func (m *QueryHostZoneResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryHostZoneResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryHostZoneResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryHostZoneResponse proto.InternalMessageInfo + +func (m *QueryHostZoneResponse) GetHostZone() *HostZone { + if m != nil { + return m.HostZone + } + return nil +} + +// All Delegation Records +type QueryDelegationRecordsRequest struct { + IncludeArchived bool `protobuf:"varint,1,opt,name=include_archived,json=includeArchived,proto3" json:"include_archived,omitempty"` +} + +func (m *QueryDelegationRecordsRequest) Reset() { *m = QueryDelegationRecordsRequest{} } +func (m *QueryDelegationRecordsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryDelegationRecordsRequest) ProtoMessage() {} +func (*QueryDelegationRecordsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{2} +} +func (m *QueryDelegationRecordsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDelegationRecordsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDelegationRecordsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryDelegationRecordsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDelegationRecordsRequest.Merge(m, src) +} +func (m *QueryDelegationRecordsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryDelegationRecordsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDelegationRecordsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDelegationRecordsRequest proto.InternalMessageInfo + +func (m *QueryDelegationRecordsRequest) GetIncludeArchived() bool { + if m != nil { + return m.IncludeArchived + } + return false +} + +type QueryDelegationRecordsResponse struct { + DelegationRecords []DelegationRecord `protobuf:"bytes,1,rep,name=delegation_records,json=delegationRecords,proto3" json:"delegation_records"` +} + +func (m *QueryDelegationRecordsResponse) Reset() { *m = QueryDelegationRecordsResponse{} } +func (m *QueryDelegationRecordsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryDelegationRecordsResponse) ProtoMessage() {} +func (*QueryDelegationRecordsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{3} +} +func (m *QueryDelegationRecordsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDelegationRecordsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDelegationRecordsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryDelegationRecordsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDelegationRecordsResponse.Merge(m, src) +} +func (m *QueryDelegationRecordsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryDelegationRecordsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDelegationRecordsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDelegationRecordsResponse proto.InternalMessageInfo + +func (m *QueryDelegationRecordsResponse) GetDelegationRecords() []DelegationRecord { + if m != nil { + return m.DelegationRecords + } + return nil +} + +// All Unbonding Records +type QueryUnbondingRecordsRequest struct { + IncludeArchived bool `protobuf:"varint,1,opt,name=include_archived,json=includeArchived,proto3" json:"include_archived,omitempty"` +} + +func (m *QueryUnbondingRecordsRequest) Reset() { *m = QueryUnbondingRecordsRequest{} } +func (m *QueryUnbondingRecordsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryUnbondingRecordsRequest) ProtoMessage() {} +func (*QueryUnbondingRecordsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{4} +} +func (m *QueryUnbondingRecordsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryUnbondingRecordsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryUnbondingRecordsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryUnbondingRecordsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryUnbondingRecordsRequest.Merge(m, src) +} +func (m *QueryUnbondingRecordsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryUnbondingRecordsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryUnbondingRecordsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryUnbondingRecordsRequest proto.InternalMessageInfo + +func (m *QueryUnbondingRecordsRequest) GetIncludeArchived() bool { + if m != nil { + return m.IncludeArchived + } + return false +} + +type QueryUnbondingRecordsResponse struct { + UnbondingRecords []UnbondingRecord `protobuf:"bytes,1,rep,name=unbonding_records,json=unbondingRecords,proto3" json:"unbonding_records"` +} + +func (m *QueryUnbondingRecordsResponse) Reset() { *m = QueryUnbondingRecordsResponse{} } +func (m *QueryUnbondingRecordsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryUnbondingRecordsResponse) ProtoMessage() {} +func (*QueryUnbondingRecordsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{5} +} +func (m *QueryUnbondingRecordsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryUnbondingRecordsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryUnbondingRecordsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryUnbondingRecordsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryUnbondingRecordsResponse.Merge(m, src) +} +func (m *QueryUnbondingRecordsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryUnbondingRecordsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryUnbondingRecordsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryUnbondingRecordsResponse proto.InternalMessageInfo + +func (m *QueryUnbondingRecordsResponse) GetUnbondingRecords() []UnbondingRecord { + if m != nil { + return m.UnbondingRecords + } + return nil +} + +// Single Redemption Record +type QueryRedemptionRecordRequest struct { + UnbondingRecordId uint64 `protobuf:"varint,1,opt,name=unbonding_record_id,json=unbondingRecordId,proto3" json:"unbonding_record_id,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` +} + +func (m *QueryRedemptionRecordRequest) Reset() { *m = QueryRedemptionRecordRequest{} } +func (m *QueryRedemptionRecordRequest) String() string { return proto.CompactTextString(m) } +func (*QueryRedemptionRecordRequest) ProtoMessage() {} +func (*QueryRedemptionRecordRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{6} +} +func (m *QueryRedemptionRecordRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRedemptionRecordRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRedemptionRecordRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryRedemptionRecordRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRedemptionRecordRequest.Merge(m, src) +} +func (m *QueryRedemptionRecordRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryRedemptionRecordRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRedemptionRecordRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRedemptionRecordRequest proto.InternalMessageInfo + +func (m *QueryRedemptionRecordRequest) GetUnbondingRecordId() uint64 { + if m != nil { + return m.UnbondingRecordId + } + return 0 +} + +func (m *QueryRedemptionRecordRequest) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +type QueryRedemptionRecordResponse struct { + RedemptionRecordResponse *RedemptionRecordResponse `protobuf:"bytes,1,opt,name=redemption_record_response,json=redemptionRecordResponse,proto3" json:"redemption_record_response,omitempty"` +} + +func (m *QueryRedemptionRecordResponse) Reset() { *m = QueryRedemptionRecordResponse{} } +func (m *QueryRedemptionRecordResponse) String() string { return proto.CompactTextString(m) } +func (*QueryRedemptionRecordResponse) ProtoMessage() {} +func (*QueryRedemptionRecordResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{7} +} +func (m *QueryRedemptionRecordResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRedemptionRecordResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRedemptionRecordResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryRedemptionRecordResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRedemptionRecordResponse.Merge(m, src) +} +func (m *QueryRedemptionRecordResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryRedemptionRecordResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRedemptionRecordResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRedemptionRecordResponse proto.InternalMessageInfo + +func (m *QueryRedemptionRecordResponse) GetRedemptionRecordResponse() *RedemptionRecordResponse { + if m != nil { + return m.RedemptionRecordResponse + } + return nil +} + +// All Redemption Records +type QueryRedemptionRecordsRequest struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + UnbondingRecordId uint64 `protobuf:"varint,2,opt,name=unbonding_record_id,json=unbondingRecordId,proto3" json:"unbonding_record_id,omitempty"` + Pagination *query.PageRequest `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryRedemptionRecordsRequest) Reset() { *m = QueryRedemptionRecordsRequest{} } +func (m *QueryRedemptionRecordsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryRedemptionRecordsRequest) ProtoMessage() {} +func (*QueryRedemptionRecordsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{8} +} +func (m *QueryRedemptionRecordsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRedemptionRecordsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRedemptionRecordsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryRedemptionRecordsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRedemptionRecordsRequest.Merge(m, src) +} +func (m *QueryRedemptionRecordsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryRedemptionRecordsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRedemptionRecordsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRedemptionRecordsRequest proto.InternalMessageInfo + +func (m *QueryRedemptionRecordsRequest) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *QueryRedemptionRecordsRequest) GetUnbondingRecordId() uint64 { + if m != nil { + return m.UnbondingRecordId + } + return 0 +} + +func (m *QueryRedemptionRecordsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +type QueryRedemptionRecordsResponse struct { + RedemptionRecordResponses []RedemptionRecordResponse `protobuf:"bytes,1,rep,name=redemption_record_responses,json=redemptionRecordResponses,proto3" json:"redemption_record_responses"` + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryRedemptionRecordsResponse) Reset() { *m = QueryRedemptionRecordsResponse{} } +func (m *QueryRedemptionRecordsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryRedemptionRecordsResponse) ProtoMessage() {} +func (*QueryRedemptionRecordsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{9} +} +func (m *QueryRedemptionRecordsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRedemptionRecordsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRedemptionRecordsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryRedemptionRecordsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRedemptionRecordsResponse.Merge(m, src) +} +func (m *QueryRedemptionRecordsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryRedemptionRecordsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRedemptionRecordsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRedemptionRecordsResponse proto.InternalMessageInfo + +func (m *QueryRedemptionRecordsResponse) GetRedemptionRecordResponses() []RedemptionRecordResponse { + if m != nil { + return m.RedemptionRecordResponses + } + return nil +} + +func (m *QueryRedemptionRecordsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +// All Slash Records +type QuerySlashRecordsRequest struct { +} + +func (m *QuerySlashRecordsRequest) Reset() { *m = QuerySlashRecordsRequest{} } +func (m *QuerySlashRecordsRequest) String() string { return proto.CompactTextString(m) } +func (*QuerySlashRecordsRequest) ProtoMessage() {} +func (*QuerySlashRecordsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{10} +} +func (m *QuerySlashRecordsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuerySlashRecordsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuerySlashRecordsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QuerySlashRecordsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySlashRecordsRequest.Merge(m, src) +} +func (m *QuerySlashRecordsRequest) XXX_Size() int { + return m.Size() +} +func (m *QuerySlashRecordsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySlashRecordsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QuerySlashRecordsRequest proto.InternalMessageInfo + +type QuerySlashRecordsResponse struct { + SlashRecords []SlashRecord `protobuf:"bytes,1,rep,name=slash_records,json=slashRecords,proto3" json:"slash_records"` +} + +func (m *QuerySlashRecordsResponse) Reset() { *m = QuerySlashRecordsResponse{} } +func (m *QuerySlashRecordsResponse) String() string { return proto.CompactTextString(m) } +func (*QuerySlashRecordsResponse) ProtoMessage() {} +func (*QuerySlashRecordsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{11} +} +func (m *QuerySlashRecordsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuerySlashRecordsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuerySlashRecordsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QuerySlashRecordsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySlashRecordsResponse.Merge(m, src) +} +func (m *QuerySlashRecordsResponse) XXX_Size() int { + return m.Size() +} +func (m *QuerySlashRecordsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySlashRecordsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QuerySlashRecordsResponse proto.InternalMessageInfo + +func (m *QuerySlashRecordsResponse) GetSlashRecords() []SlashRecord { + if m != nil { + return m.SlashRecords + } + return nil +} + +// Data structure for frontend to consume +type RedemptionRecordResponse struct { + // Redemption record + RedemptionRecord *RedemptionRecord `protobuf:"bytes,1,opt,name=redemption_record,json=redemptionRecord,proto3" json:"redemption_record,omitempty"` + // The Unix timestamp (in seconds) at which the unbonding for the UR + // associated with this RR completes + UnbondingCompletionTimeSeconds uint64 `protobuf:"varint,2,opt,name=unbonding_completion_time_seconds,json=unbondingCompletionTimeSeconds,proto3" json:"unbonding_completion_time_seconds,omitempty"` +} + +func (m *RedemptionRecordResponse) Reset() { *m = RedemptionRecordResponse{} } +func (m *RedemptionRecordResponse) String() string { return proto.CompactTextString(m) } +func (*RedemptionRecordResponse) ProtoMessage() {} +func (*RedemptionRecordResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_20841970448ef724, []int{12} +} +func (m *RedemptionRecordResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RedemptionRecordResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RedemptionRecordResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RedemptionRecordResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RedemptionRecordResponse.Merge(m, src) +} +func (m *RedemptionRecordResponse) XXX_Size() int { + return m.Size() +} +func (m *RedemptionRecordResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RedemptionRecordResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RedemptionRecordResponse proto.InternalMessageInfo + +func (m *RedemptionRecordResponse) GetRedemptionRecord() *RedemptionRecord { + if m != nil { + return m.RedemptionRecord + } + return nil +} + +func (m *RedemptionRecordResponse) GetUnbondingCompletionTimeSeconds() uint64 { + if m != nil { + return m.UnbondingCompletionTimeSeconds + } + return 0 +} + +func init() { + proto.RegisterType((*QueryHostZoneRequest)(nil), "stride.stakedym.QueryHostZoneRequest") + proto.RegisterType((*QueryHostZoneResponse)(nil), "stride.stakedym.QueryHostZoneResponse") + proto.RegisterType((*QueryDelegationRecordsRequest)(nil), "stride.stakedym.QueryDelegationRecordsRequest") + proto.RegisterType((*QueryDelegationRecordsResponse)(nil), "stride.stakedym.QueryDelegationRecordsResponse") + proto.RegisterType((*QueryUnbondingRecordsRequest)(nil), "stride.stakedym.QueryUnbondingRecordsRequest") + proto.RegisterType((*QueryUnbondingRecordsResponse)(nil), "stride.stakedym.QueryUnbondingRecordsResponse") + proto.RegisterType((*QueryRedemptionRecordRequest)(nil), "stride.stakedym.QueryRedemptionRecordRequest") + proto.RegisterType((*QueryRedemptionRecordResponse)(nil), "stride.stakedym.QueryRedemptionRecordResponse") + proto.RegisterType((*QueryRedemptionRecordsRequest)(nil), "stride.stakedym.QueryRedemptionRecordsRequest") + proto.RegisterType((*QueryRedemptionRecordsResponse)(nil), "stride.stakedym.QueryRedemptionRecordsResponse") + proto.RegisterType((*QuerySlashRecordsRequest)(nil), "stride.stakedym.QuerySlashRecordsRequest") + proto.RegisterType((*QuerySlashRecordsResponse)(nil), "stride.stakedym.QuerySlashRecordsResponse") + proto.RegisterType((*RedemptionRecordResponse)(nil), "stride.stakedym.RedemptionRecordResponse") +} + +func init() { proto.RegisterFile("stride/stakedym/query.proto", fileDescriptor_20841970448ef724) } + +var fileDescriptor_20841970448ef724 = []byte{ + // 855 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcf, 0x6f, 0xd3, 0x48, + 0x14, 0xce, 0xa4, 0xdd, 0xdd, 0x74, 0xda, 0x55, 0x93, 0xd9, 0xee, 0xca, 0x75, 0xbb, 0x26, 0xb5, + 0x44, 0x49, 0x2b, 0x6a, 0x93, 0x20, 0x15, 0xae, 0x14, 0x44, 0x29, 0xaa, 0x4a, 0x71, 0xa0, 0x87, + 0x5e, 0x22, 0x27, 0x1e, 0x39, 0x16, 0x89, 0x27, 0xf5, 0x38, 0x55, 0x4b, 0xd5, 0x0b, 0x17, 0xe0, + 0x86, 0xc4, 0x89, 0x3f, 0x81, 0x03, 0x07, 0x0e, 0xfc, 0x0f, 0xe5, 0x56, 0x89, 0x0b, 0xe2, 0x80, + 0x50, 0xcb, 0x1f, 0x82, 0x32, 0x1e, 0xe7, 0x87, 0xed, 0x49, 0x22, 0x6e, 0xce, 0xbc, 0xe7, 0xef, + 0x7d, 0xdf, 0xf3, 0x7b, 0xdf, 0x04, 0x2e, 0x50, 0xdf, 0x73, 0x2c, 0xac, 0x53, 0xdf, 0x7c, 0x86, + 0xad, 0xe3, 0xa6, 0x7e, 0xd0, 0xc6, 0xde, 0xb1, 0xd6, 0xf2, 0x88, 0x4f, 0xd0, 0x6c, 0x10, 0xd4, + 0xc2, 0xa0, 0xac, 0x44, 0xb3, 0xc3, 0x87, 0xe0, 0x05, 0x79, 0xce, 0x26, 0x36, 0x61, 0x8f, 0x7a, + 0xe7, 0x89, 0x9f, 0x2e, 0xda, 0x84, 0xd8, 0x0d, 0xac, 0x9b, 0x2d, 0x47, 0x37, 0x5d, 0x97, 0xf8, + 0xa6, 0xef, 0x10, 0x97, 0xf2, 0xe8, 0x6a, 0x8d, 0xd0, 0x26, 0xa1, 0x7a, 0xd5, 0xa4, 0x38, 0xa8, + 0xae, 0x1f, 0x16, 0xab, 0xd8, 0x37, 0x8b, 0x7a, 0xcb, 0xb4, 0x1d, 0x97, 0x25, 0x07, 0xb9, 0xea, + 0x7f, 0x70, 0xee, 0x71, 0x27, 0xe3, 0x01, 0xa1, 0xfe, 0x3e, 0x71, 0xb1, 0x81, 0x0f, 0xda, 0x98, + 0xfa, 0xea, 0x23, 0xf8, 0x6f, 0xe4, 0x9c, 0xb6, 0x88, 0x4b, 0x31, 0x5a, 0x87, 0x53, 0x75, 0x42, + 0xfd, 0xca, 0x73, 0xe2, 0x62, 0x09, 0xe4, 0x41, 0x61, 0xba, 0x34, 0xaf, 0x45, 0x54, 0x69, 0xdd, + 0xb7, 0x32, 0x75, 0xfe, 0xa4, 0x3e, 0x84, 0xff, 0x33, 0xc0, 0x7b, 0xb8, 0x81, 0x6d, 0xc6, 0xc0, + 0xc0, 0x35, 0xe2, 0x59, 0x94, 0x57, 0x44, 0x2b, 0x30, 0xeb, 0xb8, 0xb5, 0x46, 0xdb, 0xc2, 0x15, + 0xd3, 0xab, 0xd5, 0x9d, 0x43, 0x6c, 0x31, 0xfc, 0x8c, 0x31, 0xcb, 0xcf, 0xef, 0xf0, 0x63, 0xf5, + 0x08, 0x2a, 0x22, 0x2c, 0xce, 0x72, 0x0f, 0x22, 0xab, 0x1b, 0xac, 0x78, 0x41, 0x54, 0x02, 0xf9, + 0x89, 0xc2, 0x74, 0x69, 0x29, 0x46, 0x37, 0x8a, 0xb3, 0x31, 0x79, 0xf6, 0xfd, 0x4a, 0xca, 0xc8, + 0x59, 0x51, 0x7c, 0x75, 0x0b, 0x2e, 0xb2, 0xca, 0x4f, 0xdd, 0x2a, 0x71, 0x2d, 0xc7, 0xb5, 0x7f, + 0x5f, 0x84, 0xcf, 0x1b, 0x12, 0x87, 0xe2, 0x1a, 0xca, 0x30, 0xd7, 0x0e, 0x63, 0x11, 0x09, 0xf9, + 0x98, 0x84, 0x08, 0x0a, 0x57, 0x90, 0x6d, 0x47, 0xc0, 0xd5, 0x3a, 0x17, 0x60, 0x60, 0x0b, 0x37, + 0x5b, 0x3d, 0x69, 0xa1, 0x00, 0x0d, 0xfe, 0x13, 0x2d, 0x5a, 0x71, 0x02, 0x0d, 0x93, 0x46, 0x2e, + 0x02, 0xb7, 0x65, 0x21, 0x09, 0xfe, 0x65, 0x5a, 0x96, 0x87, 0x29, 0x95, 0xd2, 0x79, 0x50, 0x98, + 0x32, 0xc2, 0x9f, 0xea, 0x2b, 0xc0, 0x05, 0xc6, 0x4b, 0x71, 0x81, 0x36, 0x94, 0xbd, 0x6e, 0x2c, + 0x2c, 0xe6, 0xf1, 0x28, 0x9f, 0xad, 0x95, 0x98, 0x52, 0x11, 0x9c, 0x21, 0x79, 0x82, 0x88, 0xfa, + 0x51, 0x44, 0xa5, 0xfb, 0xdd, 0xfa, 0x64, 0x80, 0x01, 0x19, 0xa2, 0x86, 0xa4, 0x45, 0x0d, 0xb9, + 0x0f, 0x61, 0x6f, 0xc9, 0xa4, 0x09, 0x26, 0x62, 0x59, 0x0b, 0x36, 0x52, 0xeb, 0x6c, 0xa4, 0x16, + 0xf8, 0x01, 0xdf, 0x48, 0x6d, 0xd7, 0xb4, 0xc3, 0xa5, 0x33, 0xfa, 0xde, 0x54, 0xbf, 0x01, 0x3e, + 0xe4, 0x09, 0x9c, 0x79, 0xff, 0x08, 0x5c, 0x10, 0xf7, 0x2f, 0x1c, 0x95, 0xf1, 0x1b, 0xc8, 0x67, + 0x66, 0x5e, 0xd4, 0x46, 0x8a, 0x36, 0x07, 0xb4, 0xa5, 0x99, 0xb6, 0x6b, 0x23, 0xb5, 0xf1, 0xcf, + 0xd3, 0x2f, 0x4e, 0x86, 0x12, 0xd3, 0x56, 0x6e, 0x98, 0xb4, 0x3e, 0xf8, 0x29, 0x54, 0x0b, 0xce, + 0x27, 0xc4, 0xb8, 0xe4, 0x4d, 0xf8, 0x37, 0xed, 0x9c, 0x47, 0xf6, 0x61, 0x31, 0x26, 0xb2, 0xef, + 0x6d, 0xae, 0x6b, 0x86, 0xf6, 0x01, 0xaa, 0x9f, 0x00, 0x94, 0x84, 0x83, 0xb9, 0x03, 0x73, 0xb1, + 0xc6, 0xf2, 0x79, 0x5c, 0x1a, 0xdd, 0xce, 0x6c, 0xb4, 0x81, 0x68, 0x0b, 0x2e, 0xf5, 0x66, 0xa8, + 0x46, 0x9a, 0xad, 0x06, 0x66, 0xc8, 0xbe, 0xd3, 0xc4, 0x15, 0x8a, 0x6b, 0xc4, 0xb5, 0x28, 0x9f, + 0x28, 0xa5, 0x9b, 0x78, 0xb7, 0x9b, 0xf7, 0xc4, 0x69, 0xe2, 0x72, 0x90, 0x55, 0x7a, 0x99, 0x81, + 0x7f, 0xb0, 0xf6, 0xa0, 0xd7, 0x00, 0x66, 0x42, 0x9f, 0x45, 0x57, 0x63, 0xb4, 0x92, 0x5c, 0x5d, + 0x5e, 0x1e, 0x95, 0xc6, 0x17, 0x46, 0x7b, 0xf1, 0xe5, 0xe7, 0xdb, 0x74, 0x01, 0x2d, 0xeb, 0x65, + 0x96, 0xbf, 0xb6, 0x6d, 0x56, 0xa9, 0x1e, 0xbd, 0xaa, 0xba, 0xf7, 0x00, 0xfa, 0x00, 0x60, 0x2e, + 0x66, 0xc6, 0x48, 0x4b, 0xae, 0x26, 0xba, 0x01, 0x64, 0x7d, 0xec, 0x7c, 0x4e, 0xf3, 0x16, 0xa3, + 0x59, 0x44, 0xfa, 0x50, 0x9a, 0xf1, 0x8b, 0x00, 0xbd, 0x07, 0x30, 0x1b, 0xf5, 0x5d, 0xb4, 0x96, + 0x5c, 0x5e, 0x60, 0xf5, 0xb2, 0x36, 0x6e, 0x3a, 0x27, 0xbb, 0xce, 0xc8, 0xde, 0x40, 0xda, 0x50, + 0xb2, 0x31, 0xc7, 0x47, 0x9f, 0x01, 0xcc, 0x46, 0x67, 0x4c, 0xc4, 0x55, 0xe0, 0xea, 0x22, 0xae, + 0xa2, 0x05, 0x50, 0xf7, 0x18, 0xd7, 0x5d, 0xb4, 0x33, 0x94, 0x6b, 0x6c, 0x47, 0xf4, 0x93, 0x04, + 0xab, 0x3c, 0xd5, 0x4f, 0xb8, 0x97, 0x9e, 0xb2, 0x39, 0x89, 0xf9, 0x19, 0x1a, 0x93, 0xdd, 0xa8, + 0x39, 0x11, 0x1a, 0xe5, 0x98, 0x73, 0x12, 0x93, 0x43, 0xd1, 0x3b, 0x00, 0x67, 0xfa, 0x7d, 0x08, + 0xad, 0x24, 0x97, 0x4e, 0xf0, 0x31, 0x79, 0x75, 0x9c, 0x54, 0x4e, 0xb0, 0xc4, 0x08, 0x5e, 0x47, + 0xab, 0x43, 0x09, 0x0e, 0x38, 0xdf, 0xc6, 0xf6, 0xd9, 0x85, 0x02, 0xce, 0x2f, 0x14, 0xf0, 0xe3, + 0x42, 0x01, 0x6f, 0x2e, 0x95, 0xd4, 0xf9, 0xa5, 0x92, 0xfa, 0x7a, 0xa9, 0xa4, 0xf6, 0x4b, 0xb6, + 0xe3, 0xd7, 0xdb, 0x55, 0xad, 0x46, 0x9a, 0x49, 0x78, 0x87, 0xc5, 0xdb, 0xfa, 0x51, 0x0f, 0xd5, + 0x3f, 0x6e, 0x61, 0x5a, 0xfd, 0x93, 0xfd, 0x1d, 0xbc, 0xf9, 0x2b, 0x00, 0x00, 0xff, 0xff, 0xbc, + 0xb9, 0x97, 0x21, 0xbe, 0x0a, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Queries the host zone struct + HostZone(ctx context.Context, in *QueryHostZoneRequest, opts ...grpc.CallOption) (*QueryHostZoneResponse, error) + // Queries the delegation records with an optional to include archived records + // Ex: + // - /delegation_records + // - /delegation_records?include_archived=true + DelegationRecords(ctx context.Context, in *QueryDelegationRecordsRequest, opts ...grpc.CallOption) (*QueryDelegationRecordsResponse, error) + // Queries the unbonding records with an optional to include archived records + // Ex: + // - /unbonding_records + // - /unbonding_records?include_archived=true + UnbondingRecords(ctx context.Context, in *QueryUnbondingRecordsRequest, opts ...grpc.CallOption) (*QueryUnbondingRecordsResponse, error) + // Queries a single user redemption record + RedemptionRecord(ctx context.Context, in *QueryRedemptionRecordRequest, opts ...grpc.CallOption) (*QueryRedemptionRecordResponse, error) + // Queries all redemption records with optional filters + // Ex: + // - /redemption_records + // - /redemption_records?address=strideXXX + // - /redemption_records?unbonding_record_id=100 + RedemptionRecords(ctx context.Context, in *QueryRedemptionRecordsRequest, opts ...grpc.CallOption) (*QueryRedemptionRecordsResponse, error) + // Queries slash records + SlashRecords(ctx context.Context, in *QuerySlashRecordsRequest, opts ...grpc.CallOption) (*QuerySlashRecordsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) HostZone(ctx context.Context, in *QueryHostZoneRequest, opts ...grpc.CallOption) (*QueryHostZoneResponse, error) { + out := new(QueryHostZoneResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Query/HostZone", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) DelegationRecords(ctx context.Context, in *QueryDelegationRecordsRequest, opts ...grpc.CallOption) (*QueryDelegationRecordsResponse, error) { + out := new(QueryDelegationRecordsResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Query/DelegationRecords", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) UnbondingRecords(ctx context.Context, in *QueryUnbondingRecordsRequest, opts ...grpc.CallOption) (*QueryUnbondingRecordsResponse, error) { + out := new(QueryUnbondingRecordsResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Query/UnbondingRecords", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) RedemptionRecord(ctx context.Context, in *QueryRedemptionRecordRequest, opts ...grpc.CallOption) (*QueryRedemptionRecordResponse, error) { + out := new(QueryRedemptionRecordResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Query/RedemptionRecord", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) RedemptionRecords(ctx context.Context, in *QueryRedemptionRecordsRequest, opts ...grpc.CallOption) (*QueryRedemptionRecordsResponse, error) { + out := new(QueryRedemptionRecordsResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Query/RedemptionRecords", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) SlashRecords(ctx context.Context, in *QuerySlashRecordsRequest, opts ...grpc.CallOption) (*QuerySlashRecordsResponse, error) { + out := new(QuerySlashRecordsResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Query/SlashRecords", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Queries the host zone struct + HostZone(context.Context, *QueryHostZoneRequest) (*QueryHostZoneResponse, error) + // Queries the delegation records with an optional to include archived records + // Ex: + // - /delegation_records + // - /delegation_records?include_archived=true + DelegationRecords(context.Context, *QueryDelegationRecordsRequest) (*QueryDelegationRecordsResponse, error) + // Queries the unbonding records with an optional to include archived records + // Ex: + // - /unbonding_records + // - /unbonding_records?include_archived=true + UnbondingRecords(context.Context, *QueryUnbondingRecordsRequest) (*QueryUnbondingRecordsResponse, error) + // Queries a single user redemption record + RedemptionRecord(context.Context, *QueryRedemptionRecordRequest) (*QueryRedemptionRecordResponse, error) + // Queries all redemption records with optional filters + // Ex: + // - /redemption_records + // - /redemption_records?address=strideXXX + // - /redemption_records?unbonding_record_id=100 + RedemptionRecords(context.Context, *QueryRedemptionRecordsRequest) (*QueryRedemptionRecordsResponse, error) + // Queries slash records + SlashRecords(context.Context, *QuerySlashRecordsRequest) (*QuerySlashRecordsResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) HostZone(ctx context.Context, req *QueryHostZoneRequest) (*QueryHostZoneResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method HostZone not implemented") +} +func (*UnimplementedQueryServer) DelegationRecords(ctx context.Context, req *QueryDelegationRecordsRequest) (*QueryDelegationRecordsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelegationRecords not implemented") +} +func (*UnimplementedQueryServer) UnbondingRecords(ctx context.Context, req *QueryUnbondingRecordsRequest) (*QueryUnbondingRecordsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UnbondingRecords not implemented") +} +func (*UnimplementedQueryServer) RedemptionRecord(ctx context.Context, req *QueryRedemptionRecordRequest) (*QueryRedemptionRecordResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RedemptionRecord not implemented") +} +func (*UnimplementedQueryServer) RedemptionRecords(ctx context.Context, req *QueryRedemptionRecordsRequest) (*QueryRedemptionRecordsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RedemptionRecords not implemented") +} +func (*UnimplementedQueryServer) SlashRecords(ctx context.Context, req *QuerySlashRecordsRequest) (*QuerySlashRecordsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SlashRecords not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_HostZone_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryHostZoneRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).HostZone(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Query/HostZone", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).HostZone(ctx, req.(*QueryHostZoneRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_DelegationRecords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryDelegationRecordsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).DelegationRecords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Query/DelegationRecords", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).DelegationRecords(ctx, req.(*QueryDelegationRecordsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_UnbondingRecords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryUnbondingRecordsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).UnbondingRecords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Query/UnbondingRecords", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).UnbondingRecords(ctx, req.(*QueryUnbondingRecordsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_RedemptionRecord_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryRedemptionRecordRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).RedemptionRecord(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Query/RedemptionRecord", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).RedemptionRecord(ctx, req.(*QueryRedemptionRecordRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_RedemptionRecords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryRedemptionRecordsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).RedemptionRecords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Query/RedemptionRecords", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).RedemptionRecords(ctx, req.(*QueryRedemptionRecordsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_SlashRecords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QuerySlashRecordsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).SlashRecords(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Query/SlashRecords", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).SlashRecords(ctx, req.(*QuerySlashRecordsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "stride.stakedym.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "HostZone", + Handler: _Query_HostZone_Handler, + }, + { + MethodName: "DelegationRecords", + Handler: _Query_DelegationRecords_Handler, + }, + { + MethodName: "UnbondingRecords", + Handler: _Query_UnbondingRecords_Handler, + }, + { + MethodName: "RedemptionRecord", + Handler: _Query_RedemptionRecord_Handler, + }, + { + MethodName: "RedemptionRecords", + Handler: _Query_RedemptionRecords_Handler, + }, + { + MethodName: "SlashRecords", + Handler: _Query_SlashRecords_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "stride/stakedym/query.proto", +} + +func (m *QueryHostZoneRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryHostZoneRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryHostZoneRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryHostZoneResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryHostZoneResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryHostZoneResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.HostZone != nil { + { + size, err := m.HostZone.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryDelegationRecordsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryDelegationRecordsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDelegationRecordsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.IncludeArchived { + i-- + if m.IncludeArchived { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryDelegationRecordsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryDelegationRecordsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDelegationRecordsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.DelegationRecords) > 0 { + for iNdEx := len(m.DelegationRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DelegationRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryUnbondingRecordsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryUnbondingRecordsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryUnbondingRecordsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.IncludeArchived { + i-- + if m.IncludeArchived { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryUnbondingRecordsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryUnbondingRecordsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryUnbondingRecordsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.UnbondingRecords) > 0 { + for iNdEx := len(m.UnbondingRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.UnbondingRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryRedemptionRecordRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRedemptionRecordRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRedemptionRecordRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0x12 + } + if m.UnbondingRecordId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.UnbondingRecordId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryRedemptionRecordResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRedemptionRecordResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRedemptionRecordResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.RedemptionRecordResponse != nil { + { + size, err := m.RedemptionRecordResponse.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryRedemptionRecordsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRedemptionRecordsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRedemptionRecordsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.UnbondingRecordId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.UnbondingRecordId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryRedemptionRecordsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRedemptionRecordsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRedemptionRecordsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.RedemptionRecordResponses) > 0 { + for iNdEx := len(m.RedemptionRecordResponses) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RedemptionRecordResponses[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QuerySlashRecordsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QuerySlashRecordsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuerySlashRecordsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QuerySlashRecordsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QuerySlashRecordsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuerySlashRecordsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.SlashRecords) > 0 { + for iNdEx := len(m.SlashRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SlashRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *RedemptionRecordResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RedemptionRecordResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RedemptionRecordResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.UnbondingCompletionTimeSeconds != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.UnbondingCompletionTimeSeconds)) + i-- + dAtA[i] = 0x10 + } + if m.RedemptionRecord != nil { + { + size, err := m.RedemptionRecord.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryHostZoneRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryHostZoneResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.HostZone != nil { + l = m.HostZone.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryDelegationRecordsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.IncludeArchived { + n += 2 + } + return n +} + +func (m *QueryDelegationRecordsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.DelegationRecords) > 0 { + for _, e := range m.DelegationRecords { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryUnbondingRecordsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.IncludeArchived { + n += 2 + } + return n +} + +func (m *QueryUnbondingRecordsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.UnbondingRecords) > 0 { + for _, e := range m.UnbondingRecords { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryRedemptionRecordRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.UnbondingRecordId != 0 { + n += 1 + sovQuery(uint64(m.UnbondingRecordId)) + } + l = len(m.Address) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryRedemptionRecordResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.RedemptionRecordResponse != nil { + l = m.RedemptionRecordResponse.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryRedemptionRecordsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.UnbondingRecordId != 0 { + n += 1 + sovQuery(uint64(m.UnbondingRecordId)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryRedemptionRecordsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.RedemptionRecordResponses) > 0 { + for _, e := range m.RedemptionRecordResponses { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QuerySlashRecordsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QuerySlashRecordsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.SlashRecords) > 0 { + for _, e := range m.SlashRecords { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *RedemptionRecordResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.RedemptionRecord != nil { + l = m.RedemptionRecord.Size() + n += 1 + l + sovQuery(uint64(l)) + } + if m.UnbondingCompletionTimeSeconds != 0 { + n += 1 + sovQuery(uint64(m.UnbondingCompletionTimeSeconds)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryHostZoneRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryHostZoneRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryHostZoneRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryHostZoneResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryHostZoneResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryHostZoneResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostZone", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.HostZone == nil { + m.HostZone = &HostZone{} + } + if err := m.HostZone.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDelegationRecordsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryDelegationRecordsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDelegationRecordsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IncludeArchived", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IncludeArchived = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDelegationRecordsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryDelegationRecordsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDelegationRecordsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegationRecords", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegationRecords = append(m.DelegationRecords, DelegationRecord{}) + if err := m.DelegationRecords[len(m.DelegationRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryUnbondingRecordsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryUnbondingRecordsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryUnbondingRecordsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IncludeArchived", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IncludeArchived = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryUnbondingRecordsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryUnbondingRecordsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryUnbondingRecordsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingRecords", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UnbondingRecords = append(m.UnbondingRecords, UnbondingRecord{}) + if err := m.UnbondingRecords[len(m.UnbondingRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRedemptionRecordRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRedemptionRecordRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRedemptionRecordRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingRecordId", wireType) + } + m.UnbondingRecordId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnbondingRecordId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + 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 ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRedemptionRecordResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRedemptionRecordResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRedemptionRecordResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RedemptionRecordResponse", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RedemptionRecordResponse == nil { + m.RedemptionRecordResponse = &RedemptionRecordResponse{} + } + if err := m.RedemptionRecordResponse.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRedemptionRecordsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRedemptionRecordsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRedemptionRecordsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + 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 ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingRecordId", wireType) + } + m.UnbondingRecordId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnbondingRecordId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRedemptionRecordsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRedemptionRecordsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRedemptionRecordsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RedemptionRecordResponses", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RedemptionRecordResponses = append(m.RedemptionRecordResponses, RedemptionRecordResponse{}) + if err := m.RedemptionRecordResponses[len(m.RedemptionRecordResponses)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QuerySlashRecordsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QuerySlashRecordsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuerySlashRecordsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QuerySlashRecordsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QuerySlashRecordsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuerySlashRecordsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SlashRecords", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SlashRecords = append(m.SlashRecords, SlashRecord{}) + if err := m.SlashRecords[len(m.SlashRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RedemptionRecordResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RedemptionRecordResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RedemptionRecordResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RedemptionRecord", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RedemptionRecord == nil { + m.RedemptionRecord = &RedemptionRecord{} + } + if err := m.RedemptionRecord.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingCompletionTimeSeconds", wireType) + } + m.UnbondingCompletionTimeSeconds = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnbondingCompletionTimeSeconds |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/stakedym/types/query.pb.gw.go b/x/stakedym/types/query.pb.gw.go new file mode 100644 index 0000000000..2beb8c97ff --- /dev/null +++ b/x/stakedym/types/query.pb.gw.go @@ -0,0 +1,590 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: stride/stakedym/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_HostZone_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryHostZoneRequest + var metadata runtime.ServerMetadata + + msg, err := client.HostZone(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_HostZone_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryHostZoneRequest + var metadata runtime.ServerMetadata + + msg, err := server.HostZone(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_DelegationRecords_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_DelegationRecords_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDelegationRecordsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_DelegationRecords_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.DelegationRecords(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_DelegationRecords_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDelegationRecordsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_DelegationRecords_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.DelegationRecords(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_UnbondingRecords_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_UnbondingRecords_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryUnbondingRecordsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_UnbondingRecords_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UnbondingRecords(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_UnbondingRecords_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryUnbondingRecordsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_UnbondingRecords_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.UnbondingRecords(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_RedemptionRecord_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRedemptionRecordRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["unbonding_record_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "unbonding_record_id") + } + + protoReq.UnbondingRecordId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "unbonding_record_id", err) + } + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + msg, err := client.RedemptionRecord(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_RedemptionRecord_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRedemptionRecordRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["unbonding_record_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "unbonding_record_id") + } + + protoReq.UnbondingRecordId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "unbonding_record_id", err) + } + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + msg, err := server.RedemptionRecord(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_RedemptionRecords_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_RedemptionRecords_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRedemptionRecordsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_RedemptionRecords_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.RedemptionRecords(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_RedemptionRecords_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRedemptionRecordsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_RedemptionRecords_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.RedemptionRecords(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_SlashRecords_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySlashRecordsRequest + var metadata runtime.ServerMetadata + + msg, err := client.SlashRecords(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_SlashRecords_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySlashRecordsRequest + var metadata runtime.ServerMetadata + + msg, err := server.SlashRecords(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_HostZone_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_HostZone_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_HostZone_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DelegationRecords_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_DelegationRecords_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DelegationRecords_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_UnbondingRecords_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_UnbondingRecords_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_UnbondingRecords_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RedemptionRecord_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_RedemptionRecord_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RedemptionRecord_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RedemptionRecords_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_RedemptionRecords_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RedemptionRecords_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_SlashRecords_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_SlashRecords_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_SlashRecords_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_HostZone_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_HostZone_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_HostZone_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DelegationRecords_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_DelegationRecords_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DelegationRecords_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_UnbondingRecords_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_UnbondingRecords_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_UnbondingRecords_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RedemptionRecord_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_RedemptionRecord_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RedemptionRecord_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RedemptionRecords_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_RedemptionRecords_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RedemptionRecords_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_SlashRecords_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_SlashRecords_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_SlashRecords_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_HostZone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"Stride-Labs", "stride", "stakedym", "host_zone"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_DelegationRecords_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"Stride-Labs", "stride", "stakedym", "delegation_records"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_UnbondingRecords_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"Stride-Labs", "stride", "stakedym", "unbonding_records"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_RedemptionRecord_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"Stride-Labs", "stride", "stakedym", "redemption_record", "unbonding_record_id", "address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_RedemptionRecords_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"Stride-Labs", "stride", "stakedym", "redemption_records"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_SlashRecords_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"Stride-Labs", "stride", "stakedym", "slash_records"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_HostZone_0 = runtime.ForwardResponseMessage + + forward_Query_DelegationRecords_0 = runtime.ForwardResponseMessage + + forward_Query_UnbondingRecords_0 = runtime.ForwardResponseMessage + + forward_Query_RedemptionRecord_0 = runtime.ForwardResponseMessage + + forward_Query_RedemptionRecords_0 = runtime.ForwardResponseMessage + + forward_Query_SlashRecords_0 = runtime.ForwardResponseMessage +) diff --git a/x/stakedym/types/records.go b/x/stakedym/types/records.go new file mode 100644 index 0000000000..da04cbbb9b --- /dev/null +++ b/x/stakedym/types/records.go @@ -0,0 +1,83 @@ +package types + +import ( + fmt "fmt" +) + +// Confirm there are no duplicate delegation record Ids and that the amounts are not nil +func ValidateDelegationRecordGenesis(delegationRecords []DelegationRecord) error { + ids := map[uint64]bool{} + for _, delegationRecord := range delegationRecords { + if delegationRecord.NativeAmount.IsNil() { + return ErrInvalidGenesisRecords.Wrapf("uninitialized native amount in delegation record %d", delegationRecord.Id) + } + if _, ok := ids[delegationRecord.Id]; ok { + return ErrInvalidGenesisRecords.Wrapf("duplicate delegation record %d", delegationRecord.Id) + } + ids[delegationRecord.Id] = true + } + return nil +} + +// Confirm there are no duplicate unbonding record Ids and that the amounts are not nil +func ValidateUnbondingRecordGenesis(unbondingRecords []UnbondingRecord) error { + ids := map[uint64]bool{} + for _, unbondingRecord := range unbondingRecords { + if unbondingRecord.NativeAmount.IsNil() { + return ErrInvalidGenesisRecords.Wrapf("uninitialized native amount in unbonding record %d", unbondingRecord.Id) + } + if unbondingRecord.StTokenAmount.IsNil() { + return ErrInvalidGenesisRecords.Wrapf("uninitialized sttoken amount in unbonding record %d", unbondingRecord.Id) + } + if _, ok := ids[unbondingRecord.Id]; ok { + return ErrInvalidGenesisRecords.Wrapf("duplicate unbonding record %d", unbondingRecord.Id) + } + ids[unbondingRecord.Id] = true + } + return nil +} + +// Confirm there are no duplicate slash record Ids and that the amounts are not nil +func ValidateRedemptionRecordGenesis(redemptionRecords []RedemptionRecord) error { + ids := map[string]bool{} + for _, redemptionRecord := range redemptionRecords { + idKey := fmt.Sprintf("%d-%s", redemptionRecord.UnbondingRecordId, redemptionRecord.Redeemer) + + if redemptionRecord.NativeAmount.IsNil() { + return ErrInvalidGenesisRecords.Wrapf("uninitialized native amount in redemption record %s", idKey) + } + if redemptionRecord.StTokenAmount.IsNil() { + return ErrInvalidGenesisRecords.Wrapf("uninitialized sttoken amount in redemption record %s", idKey) + } + + if _, ok := ids[idKey]; ok { + return ErrInvalidGenesisRecords.Wrapf("duplicate redemption record %s", idKey) + } + ids[idKey] = true + } + + return nil +} + +// Confirm there are no duplicate slash record Ids and that the amounts are not nil +func ValidateSlashRecordGenesis(slashRecords []SlashRecord) error { + ids := map[uint64]bool{} + for _, slashRecord := range slashRecords { + if slashRecord.NativeAmount.IsNil() { + return ErrInvalidGenesisRecords.Wrapf("uninitialized native amount in slash record %d", slashRecord.Id) + } + if _, ok := ids[slashRecord.Id]; ok { + return ErrInvalidGenesisRecords.Wrapf("duplicate slash record %d", slashRecord.Id) + } + ids[slashRecord.Id] = true + } + return nil +} + +// Returns a RedemptionRecordResponse, which is a RedemptionRecord with the unbonding time +func NewRedemptionRecordResponse(redemptionRecord RedemptionRecord, unbondingTime uint64) RedemptionRecordResponse { + return RedemptionRecordResponse{ + RedemptionRecord: &redemptionRecord, + UnbondingCompletionTimeSeconds: unbondingTime, + } +} diff --git a/x/stakedym/types/records_test.go b/x/stakedym/types/records_test.go new file mode 100644 index 0000000000..261a83fe22 --- /dev/null +++ b/x/stakedym/types/records_test.go @@ -0,0 +1,213 @@ +package types_test + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + + "github.com/stretchr/testify/require" + + "github.com/Stride-Labs/stride/v18/x/stakedym/types" +) + +func TestValidateDelegationRecordGenesis(t *testing.T) { + testCases := []struct { + name string + delegationRecords []types.DelegationRecord + expectedError string + }{ + { + name: "valid records", + delegationRecords: []types.DelegationRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(1)}, + {Id: 2, NativeAmount: sdkmath.NewInt(2)}, + {Id: 3, NativeAmount: sdkmath.NewInt(3)}, + }, + }, + { + name: "duplicate records", + delegationRecords: []types.DelegationRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(1)}, + {Id: 2, NativeAmount: sdkmath.NewInt(2)}, + {Id: 1, NativeAmount: sdkmath.NewInt(3)}, + }, + expectedError: "duplicate delegation record 1", + }, + { + name: "uninitialized native amount", + delegationRecords: []types.DelegationRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(1)}, + {Id: 2}, + {Id: 3, NativeAmount: sdkmath.NewInt(3)}, + }, + expectedError: "uninitialized native amount in delegation record 2", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := types.ValidateDelegationRecordGenesis(tc.delegationRecords) + if tc.expectedError == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tc.expectedError) + } + }) + } +} + +func TestValidateUnbondingRecordGenesis(t *testing.T) { + testCases := []struct { + name string + unbondingRecords []types.UnbondingRecord + expectedError string + }{ + { + name: "valid records", + unbondingRecords: []types.UnbondingRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(1), StTokenAmount: sdkmath.NewInt(1)}, + {Id: 2, NativeAmount: sdkmath.NewInt(2), StTokenAmount: sdkmath.NewInt(2)}, + {Id: 3, NativeAmount: sdkmath.NewInt(3), StTokenAmount: sdkmath.NewInt(3)}, + }, + }, + { + name: "duplicate records", + unbondingRecords: []types.UnbondingRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(1), StTokenAmount: sdkmath.NewInt(1)}, + {Id: 2, NativeAmount: sdkmath.NewInt(2), StTokenAmount: sdkmath.NewInt(2)}, + {Id: 1, NativeAmount: sdkmath.NewInt(3), StTokenAmount: sdkmath.NewInt(3)}, + }, + expectedError: "duplicate unbonding record 1", + }, + { + name: "uninitialized native amount", + unbondingRecords: []types.UnbondingRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(1), StTokenAmount: sdkmath.NewInt(1)}, + {Id: 2, StTokenAmount: sdkmath.NewInt(2)}, + {Id: 3, NativeAmount: sdkmath.NewInt(3), StTokenAmount: sdkmath.NewInt(3)}, + }, + expectedError: "uninitialized native amount in unbonding record 2", + }, + { + name: "uninitialized st amount", + unbondingRecords: []types.UnbondingRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(1), StTokenAmount: sdkmath.NewInt(1)}, + {Id: 2, NativeAmount: sdkmath.NewInt(2), StTokenAmount: sdkmath.NewInt(2)}, + {Id: 3, NativeAmount: sdkmath.NewInt(3)}, + }, + expectedError: "uninitialized sttoken amount in unbonding record 3", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := types.ValidateUnbondingRecordGenesis(tc.unbondingRecords) + if tc.expectedError == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tc.expectedError) + } + }) + } +} + +func TestValidateRedemptionRecordGenesis(t *testing.T) { + testCases := []struct { + name string + redemptionRecord []types.RedemptionRecord + expectedError string + }{ + { + name: "valid records", + redemptionRecord: []types.RedemptionRecord{ + {UnbondingRecordId: 1, Redeemer: "A", NativeAmount: sdkmath.NewInt(1), StTokenAmount: sdkmath.NewInt(1)}, + {UnbondingRecordId: 2, Redeemer: "A", NativeAmount: sdkmath.NewInt(2), StTokenAmount: sdkmath.NewInt(2)}, + {UnbondingRecordId: 3, Redeemer: "A", NativeAmount: sdkmath.NewInt(3), StTokenAmount: sdkmath.NewInt(3)}, + }, + }, + { + name: "duplicate records", + redemptionRecord: []types.RedemptionRecord{ + {UnbondingRecordId: 1, Redeemer: "A", NativeAmount: sdkmath.NewInt(1), StTokenAmount: sdkmath.NewInt(1)}, + {UnbondingRecordId: 2, Redeemer: "A", NativeAmount: sdkmath.NewInt(2), StTokenAmount: sdkmath.NewInt(2)}, + {UnbondingRecordId: 1, Redeemer: "A", NativeAmount: sdkmath.NewInt(3), StTokenAmount: sdkmath.NewInt(3)}, + }, + expectedError: "duplicate redemption record 1-A", + }, + { + name: "uninitialized native amount", + redemptionRecord: []types.RedemptionRecord{ + {UnbondingRecordId: 1, Redeemer: "A", NativeAmount: sdkmath.NewInt(1), StTokenAmount: sdkmath.NewInt(1)}, + {UnbondingRecordId: 2, Redeemer: "A", StTokenAmount: sdkmath.NewInt(2)}, + {UnbondingRecordId: 3, Redeemer: "A", NativeAmount: sdkmath.NewInt(3), StTokenAmount: sdkmath.NewInt(3)}, + }, + expectedError: "uninitialized native amount in redemption record 2-A", + }, + { + name: "uninitialized st amount", + redemptionRecord: []types.RedemptionRecord{ + {UnbondingRecordId: 1, Redeemer: "A", NativeAmount: sdkmath.NewInt(1), StTokenAmount: sdkmath.NewInt(1)}, + {UnbondingRecordId: 2, Redeemer: "A", NativeAmount: sdkmath.NewInt(2), StTokenAmount: sdkmath.NewInt(2)}, + {UnbondingRecordId: 3, Redeemer: "A", NativeAmount: sdkmath.NewInt(3)}, + }, + expectedError: "uninitialized sttoken amount in redemption record 3-A", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := types.ValidateRedemptionRecordGenesis(tc.redemptionRecord) + if tc.expectedError == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tc.expectedError) + } + }) + } +} + +func TestValidateSlashRecordGenesis(t *testing.T) { + testCases := []struct { + name string + slashRecords []types.SlashRecord + expectedError string + }{ + { + name: "valid records", + slashRecords: []types.SlashRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(1)}, + {Id: 2, NativeAmount: sdkmath.NewInt(2)}, + {Id: 3, NativeAmount: sdkmath.NewInt(3)}, + }, + }, + { + name: "duplicate records", + slashRecords: []types.SlashRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(1)}, + {Id: 2, NativeAmount: sdkmath.NewInt(2)}, + {Id: 1, NativeAmount: sdkmath.NewInt(3)}, + }, + expectedError: "duplicate slash record 1", + }, + { + name: "uninitialized native amount", + slashRecords: []types.SlashRecord{ + {Id: 1, NativeAmount: sdkmath.NewInt(1)}, + {Id: 2}, + {Id: 3, NativeAmount: sdkmath.NewInt(3)}, + }, + expectedError: "uninitialized native amount in slash record 2", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := types.ValidateSlashRecordGenesis(tc.slashRecords) + if tc.expectedError == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tc.expectedError) + } + }) + } +} diff --git a/x/stakedym/types/stakedym.pb.go b/x/stakedym/types/stakedym.pb.go new file mode 100644 index 0000000000..a934a1277f --- /dev/null +++ b/x/stakedym/types/stakedym.pb.go @@ -0,0 +1,2740 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: stride/stakedym/stakedym.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Status fields for a delegation record +// Note: There is an important assumption here that tokens in the deposit +// account should not be tracked by these records. The record is created as soon +// as the tokens leave stride +// Additionally, the GetActiveDelegationRecords query filters for records that +// are either TRANSFER_IN_PROGERSS or DELEGATION_QUEUE. If a new active status +// is added, the keeper must be modified +type DelegationRecordStatus int32 + +const ( + // TRANSFER_IN_PROGRESS indicates the native tokens are being sent from the + // deposit account to the delegation account + TRANSFER_IN_PROGRESS DelegationRecordStatus = 0 + // TRANSFER_FAILED indicates that the transfer either timed out or was an ack + // failure + TRANSFER_FAILED DelegationRecordStatus = 1 + // DELEGATION_QUEUE indicates the tokens have landed on the host zone and are + // ready to be delegated + DELEGATION_QUEUE DelegationRecordStatus = 2 + // DELEGATION_COMPLETE indicates the delegation has been completed + DELEGATION_COMPLETE DelegationRecordStatus = 3 +) + +var DelegationRecordStatus_name = map[int32]string{ + 0: "TRANSFER_IN_PROGRESS", + 1: "TRANSFER_FAILED", + 2: "DELEGATION_QUEUE", + 3: "DELEGATION_COMPLETE", +} + +var DelegationRecordStatus_value = map[string]int32{ + "TRANSFER_IN_PROGRESS": 0, + "TRANSFER_FAILED": 1, + "DELEGATION_QUEUE": 2, + "DELEGATION_COMPLETE": 3, +} + +func (x DelegationRecordStatus) String() string { + return proto.EnumName(DelegationRecordStatus_name, int32(x)) +} + +func (DelegationRecordStatus) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_d78132ac6adfd885, []int{0} +} + +// Status fields for an unbonding record +type UnbondingRecordStatus int32 + +const ( + // ACCUMULATING_REDEMPTIONS indicates redemptions are still being accumulated + // on this record + ACCUMULATING_REDEMPTIONS UnbondingRecordStatus = 0 + // UNBONDING_QUEUE indicates the unbond amount for this epoch has been froze + // and the tokens are ready to be unbonded on the host zone + UNBONDING_QUEUE UnbondingRecordStatus = 1 + // UNBONDING_IN_PROGRESS indicates the unbonding is currently in progress on + // the host zone + UNBONDING_IN_PROGRESS UnbondingRecordStatus = 2 + // UNBONDED indicates the unbonding is finished on the host zone and the + // tokens are still in the delegation account + UNBONDED UnbondingRecordStatus = 3 + // CLAIMABLE indicates the unbonded tokens have been swept to stride and are + // ready to be distributed to users + CLAIMABLE UnbondingRecordStatus = 4 + // CLAIMED indicates the full unbonding cycle has been completed + CLAIMED UnbondingRecordStatus = 5 +) + +var UnbondingRecordStatus_name = map[int32]string{ + 0: "ACCUMULATING_REDEMPTIONS", + 1: "UNBONDING_QUEUE", + 2: "UNBONDING_IN_PROGRESS", + 3: "UNBONDED", + 4: "CLAIMABLE", + 5: "CLAIMED", +} + +var UnbondingRecordStatus_value = map[string]int32{ + "ACCUMULATING_REDEMPTIONS": 0, + "UNBONDING_QUEUE": 1, + "UNBONDING_IN_PROGRESS": 2, + "UNBONDED": 3, + "CLAIMABLE": 4, + "CLAIMED": 5, +} + +func (x UnbondingRecordStatus) String() string { + return proto.EnumName(UnbondingRecordStatus_name, int32(x)) +} + +func (UnbondingRecordStatus) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_d78132ac6adfd885, []int{1} +} + +type HostZone struct { + // Chain ID + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // Native token denom on the host zone (e.g. adym) + NativeTokenDenom string `protobuf:"bytes,2,opt,name=native_token_denom,json=nativeTokenDenom,proto3" json:"native_token_denom,omitempty"` + // IBC denom of the native token as it lives on stride (e.g. ibc/...) + NativeTokenIbcDenom string `protobuf:"bytes,3,opt,name=native_token_ibc_denom,json=nativeTokenIbcDenom,proto3" json:"native_token_ibc_denom,omitempty"` + // Transfer channel ID from stride to the host zone + TransferChannelId string `protobuf:"bytes,4,opt,name=transfer_channel_id,json=transferChannelId,proto3" json:"transfer_channel_id,omitempty"` + // Operator controlled delegation address on the host zone + DelegationAddress string `protobuf:"bytes,5,opt,name=delegation_address,json=delegationAddress,proto3" json:"delegation_address,omitempty"` + // Operator controlled reward address on the host zone + RewardAddress string `protobuf:"bytes,6,opt,name=reward_address,json=rewardAddress,proto3" json:"reward_address,omitempty"` + // Deposit address on stride + DepositAddress string `protobuf:"bytes,7,opt,name=deposit_address,json=depositAddress,proto3" json:"deposit_address,omitempty"` + // Redemption address on stride + RedemptionAddress string `protobuf:"bytes,8,opt,name=redemption_address,json=redemptionAddress,proto3" json:"redemption_address,omitempty"` + // Claim address on stride + ClaimAddress string `protobuf:"bytes,9,opt,name=claim_address,json=claimAddress,proto3" json:"claim_address,omitempty"` + // operator address set by safe, on stride + OperatorAddressOnStride string `protobuf:"bytes,10,opt,name=operator_address_on_stride,json=operatorAddressOnStride,proto3" json:"operator_address_on_stride,omitempty"` + // admin address set upon host zone creation, on stride + SafeAddressOnStride string `protobuf:"bytes,11,opt,name=safe_address_on_stride,json=safeAddressOnStride,proto3" json:"safe_address_on_stride,omitempty"` + // Previous redemption rate + LastRedemptionRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,12,opt,name=last_redemption_rate,json=lastRedemptionRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"last_redemption_rate"` + // Current redemption rate + RedemptionRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,13,opt,name=redemption_rate,json=redemptionRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"redemption_rate"` + // Min outer redemption rate - adjusted by governance + MinRedemptionRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,14,opt,name=min_redemption_rate,json=minRedemptionRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"min_redemption_rate"` + // Max outer redemption rate - adjusted by governance + MaxRedemptionRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,15,opt,name=max_redemption_rate,json=maxRedemptionRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"max_redemption_rate"` + // Min inner redemption rate - adjusted by controller + MinInnerRedemptionRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,16,opt,name=min_inner_redemption_rate,json=minInnerRedemptionRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"min_inner_redemption_rate"` + // Max inner redemption rate - adjusted by controller + MaxInnerRedemptionRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,17,opt,name=max_inner_redemption_rate,json=maxInnerRedemptionRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"max_inner_redemption_rate"` + // Total delegated balance on the host zone delegation account + DelegatedBalance github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,18,opt,name=delegated_balance,json=delegatedBalance,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"delegated_balance"` + // The undelegation period for Dymension in days + UnbondingPeriodSeconds uint64 `protobuf:"varint,19,opt,name=unbonding_period_seconds,json=unbondingPeriodSeconds,proto3" json:"unbonding_period_seconds,omitempty"` + // Indicates whether the host zone has been halted + Halted bool `protobuf:"varint,20,opt,name=halted,proto3" json:"halted,omitempty"` +} + +func (m *HostZone) Reset() { *m = HostZone{} } +func (m *HostZone) String() string { return proto.CompactTextString(m) } +func (*HostZone) ProtoMessage() {} +func (*HostZone) Descriptor() ([]byte, []int) { + return fileDescriptor_d78132ac6adfd885, []int{0} +} +func (m *HostZone) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *HostZone) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_HostZone.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *HostZone) XXX_Merge(src proto.Message) { + xxx_messageInfo_HostZone.Merge(m, src) +} +func (m *HostZone) XXX_Size() int { + return m.Size() +} +func (m *HostZone) XXX_DiscardUnknown() { + xxx_messageInfo_HostZone.DiscardUnknown(m) +} + +var xxx_messageInfo_HostZone proto.InternalMessageInfo + +func (m *HostZone) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + +func (m *HostZone) GetNativeTokenDenom() string { + if m != nil { + return m.NativeTokenDenom + } + return "" +} + +func (m *HostZone) GetNativeTokenIbcDenom() string { + if m != nil { + return m.NativeTokenIbcDenom + } + return "" +} + +func (m *HostZone) GetTransferChannelId() string { + if m != nil { + return m.TransferChannelId + } + return "" +} + +func (m *HostZone) GetDelegationAddress() string { + if m != nil { + return m.DelegationAddress + } + return "" +} + +func (m *HostZone) GetRewardAddress() string { + if m != nil { + return m.RewardAddress + } + return "" +} + +func (m *HostZone) GetDepositAddress() string { + if m != nil { + return m.DepositAddress + } + return "" +} + +func (m *HostZone) GetRedemptionAddress() string { + if m != nil { + return m.RedemptionAddress + } + return "" +} + +func (m *HostZone) GetClaimAddress() string { + if m != nil { + return m.ClaimAddress + } + return "" +} + +func (m *HostZone) GetOperatorAddressOnStride() string { + if m != nil { + return m.OperatorAddressOnStride + } + return "" +} + +func (m *HostZone) GetSafeAddressOnStride() string { + if m != nil { + return m.SafeAddressOnStride + } + return "" +} + +func (m *HostZone) GetUnbondingPeriodSeconds() uint64 { + if m != nil { + return m.UnbondingPeriodSeconds + } + return 0 +} + +func (m *HostZone) GetHalted() bool { + if m != nil { + return m.Halted + } + return false +} + +// DelegationRecords track the aggregate liquid stakes and delegations +// for a given epoch +// Note: There is an important assumption here that tokens in the deposit +// account should not be tracked by these records. The record is created as soon +// as the tokens leave stride +type DelegationRecord struct { + // Deposit record unique ID + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + // The amount of native tokens that should be delegated + NativeAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=native_amount,json=nativeAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"native_amount"` + // The status indicating the point in the delegation's lifecycle + Status DelegationRecordStatus `protobuf:"varint,3,opt,name=status,proto3,enum=stride.stakedym.DelegationRecordStatus" json:"status,omitempty"` + // The tx hash of the delegation on the host zone + TxHash string `protobuf:"bytes,4,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` +} + +func (m *DelegationRecord) Reset() { *m = DelegationRecord{} } +func (m *DelegationRecord) String() string { return proto.CompactTextString(m) } +func (*DelegationRecord) ProtoMessage() {} +func (*DelegationRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_d78132ac6adfd885, []int{1} +} +func (m *DelegationRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DelegationRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DelegationRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DelegationRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_DelegationRecord.Merge(m, src) +} +func (m *DelegationRecord) XXX_Size() int { + return m.Size() +} +func (m *DelegationRecord) XXX_DiscardUnknown() { + xxx_messageInfo_DelegationRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_DelegationRecord proto.InternalMessageInfo + +func (m *DelegationRecord) GetId() uint64 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *DelegationRecord) GetStatus() DelegationRecordStatus { + if m != nil { + return m.Status + } + return TRANSFER_IN_PROGRESS +} + +func (m *DelegationRecord) GetTxHash() string { + if m != nil { + return m.TxHash + } + return "" +} + +// UnbondingRecords track the aggregate unbondings across an epoch +type UnbondingRecord struct { + // Unbonding record ID + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + // The status indicating the point in the delegation's lifecycle + Status UnbondingRecordStatus `protobuf:"varint,2,opt,name=status,proto3,enum=stride.stakedym.UnbondingRecordStatus" json:"status,omitempty"` + // The amount of stTokens that were redeemed + StTokenAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=st_token_amount,json=stTokenAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"st_token_amount"` + // The corresponding amount of native tokens that should be unbonded + NativeAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=native_amount,json=nativeAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"native_amount"` + // The Unix timestamp (in seconds) at which the unbonding completes + UnbondingCompletionTimeSeconds uint64 `protobuf:"varint,5,opt,name=unbonding_completion_time_seconds,json=unbondingCompletionTimeSeconds,proto3" json:"unbonding_completion_time_seconds,omitempty"` + // The tx hash of the undelegation on the host zone + UndelegationTxHash string `protobuf:"bytes,6,opt,name=undelegation_tx_hash,json=undelegationTxHash,proto3" json:"undelegation_tx_hash,omitempty"` + // The tx hash of the unbonded token sweep on the host zone + UnbondedTokenSweepTxHash string `protobuf:"bytes,7,opt,name=unbonded_token_sweep_tx_hash,json=unbondedTokenSweepTxHash,proto3" json:"unbonded_token_sweep_tx_hash,omitempty"` +} + +func (m *UnbondingRecord) Reset() { *m = UnbondingRecord{} } +func (m *UnbondingRecord) String() string { return proto.CompactTextString(m) } +func (*UnbondingRecord) ProtoMessage() {} +func (*UnbondingRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_d78132ac6adfd885, []int{2} +} +func (m *UnbondingRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UnbondingRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UnbondingRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UnbondingRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_UnbondingRecord.Merge(m, src) +} +func (m *UnbondingRecord) XXX_Size() int { + return m.Size() +} +func (m *UnbondingRecord) XXX_DiscardUnknown() { + xxx_messageInfo_UnbondingRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_UnbondingRecord proto.InternalMessageInfo + +func (m *UnbondingRecord) GetId() uint64 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *UnbondingRecord) GetStatus() UnbondingRecordStatus { + if m != nil { + return m.Status + } + return ACCUMULATING_REDEMPTIONS +} + +func (m *UnbondingRecord) GetUnbondingCompletionTimeSeconds() uint64 { + if m != nil { + return m.UnbondingCompletionTimeSeconds + } + return 0 +} + +func (m *UnbondingRecord) GetUndelegationTxHash() string { + if m != nil { + return m.UndelegationTxHash + } + return "" +} + +func (m *UnbondingRecord) GetUnbondedTokenSweepTxHash() string { + if m != nil { + return m.UnbondedTokenSweepTxHash + } + return "" +} + +// RedemptionRecords track an individual user's redemption claims +type RedemptionRecord struct { + // Unbonding record ID + UnbondingRecordId uint64 `protobuf:"varint,1,opt,name=unbonding_record_id,json=unbondingRecordId,proto3" json:"unbonding_record_id,omitempty"` + // Redeemer + Redeemer string `protobuf:"bytes,2,opt,name=redeemer,proto3" json:"redeemer,omitempty"` + // The amount of stTokens that were redeemed + StTokenAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=st_token_amount,json=stTokenAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"st_token_amount"` + // The corresponding amount of native tokens that should be unbonded + NativeAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=native_amount,json=nativeAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"native_amount"` +} + +func (m *RedemptionRecord) Reset() { *m = RedemptionRecord{} } +func (m *RedemptionRecord) String() string { return proto.CompactTextString(m) } +func (*RedemptionRecord) ProtoMessage() {} +func (*RedemptionRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_d78132ac6adfd885, []int{3} +} +func (m *RedemptionRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RedemptionRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RedemptionRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RedemptionRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_RedemptionRecord.Merge(m, src) +} +func (m *RedemptionRecord) XXX_Size() int { + return m.Size() +} +func (m *RedemptionRecord) XXX_DiscardUnknown() { + xxx_messageInfo_RedemptionRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_RedemptionRecord proto.InternalMessageInfo + +func (m *RedemptionRecord) GetUnbondingRecordId() uint64 { + if m != nil { + return m.UnbondingRecordId + } + return 0 +} + +func (m *RedemptionRecord) GetRedeemer() string { + if m != nil { + return m.Redeemer + } + return "" +} + +// SlashRecords log adjustments to the delegated balance +type SlashRecord struct { + // The slash record monotonically increasing ID + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + // The Unix timestamp (in seconds) when the slash adjustment was processed on + // stride + Time uint64 `protobuf:"varint,2,opt,name=time,proto3" json:"time,omitempty"` + // The delta by which the total delegated amount changed from slash + NativeAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=native_amount,json=nativeAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"native_amount"` + // The address (or addresses) of the validator that was slashed + ValidatorAddress string `protobuf:"bytes,4,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"` +} + +func (m *SlashRecord) Reset() { *m = SlashRecord{} } +func (m *SlashRecord) String() string { return proto.CompactTextString(m) } +func (*SlashRecord) ProtoMessage() {} +func (*SlashRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_d78132ac6adfd885, []int{4} +} +func (m *SlashRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SlashRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SlashRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SlashRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_SlashRecord.Merge(m, src) +} +func (m *SlashRecord) XXX_Size() int { + return m.Size() +} +func (m *SlashRecord) XXX_DiscardUnknown() { + xxx_messageInfo_SlashRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_SlashRecord proto.InternalMessageInfo + +func (m *SlashRecord) GetId() uint64 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *SlashRecord) GetTime() uint64 { + if m != nil { + return m.Time + } + return 0 +} + +func (m *SlashRecord) GetValidatorAddress() string { + if m != nil { + return m.ValidatorAddress + } + return "" +} + +func init() { + proto.RegisterEnum("stride.stakedym.DelegationRecordStatus", DelegationRecordStatus_name, DelegationRecordStatus_value) + proto.RegisterEnum("stride.stakedym.UnbondingRecordStatus", UnbondingRecordStatus_name, UnbondingRecordStatus_value) + proto.RegisterType((*HostZone)(nil), "stride.stakedym.HostZone") + proto.RegisterType((*DelegationRecord)(nil), "stride.stakedym.DelegationRecord") + proto.RegisterType((*UnbondingRecord)(nil), "stride.stakedym.UnbondingRecord") + proto.RegisterType((*RedemptionRecord)(nil), "stride.stakedym.RedemptionRecord") + proto.RegisterType((*SlashRecord)(nil), "stride.stakedym.SlashRecord") +} + +func init() { proto.RegisterFile("stride/stakedym/stakedym.proto", fileDescriptor_d78132ac6adfd885) } + +var fileDescriptor_d78132ac6adfd885 = []byte{ + // 1121 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x57, 0xcf, 0x6f, 0x1a, 0xc7, + 0x17, 0x67, 0x81, 0xd8, 0xe4, 0xc5, 0xc0, 0x32, 0x10, 0xb2, 0xb6, 0x22, 0xe2, 0xaf, 0x0f, 0xf9, + 0x5a, 0x69, 0x8d, 0xdb, 0xe4, 0x92, 0x43, 0x9b, 0x08, 0xc3, 0xc6, 0x59, 0x09, 0x63, 0x77, 0x81, + 0x1e, 0xd2, 0xc3, 0x6a, 0xd8, 0x9d, 0xc0, 0xca, 0xec, 0x2c, 0xda, 0x19, 0x6c, 0x22, 0xf5, 0xde, + 0x4a, 0xbd, 0xf4, 0xd2, 0xbf, 0xa0, 0x7f, 0x42, 0xf3, 0x47, 0x44, 0xea, 0x25, 0xcd, 0xa9, 0xea, + 0x21, 0xaa, 0xec, 0x7f, 0xa4, 0xda, 0xd9, 0x1f, 0x60, 0xb0, 0x85, 0x52, 0x71, 0xe9, 0x89, 0x9d, + 0xf7, 0x79, 0xef, 0xf3, 0x99, 0xf7, 0xde, 0xcc, 0xbe, 0x05, 0x2a, 0x8c, 0x7b, 0xb6, 0x45, 0xf6, + 0x19, 0xc7, 0xa7, 0xc4, 0x7a, 0xe3, 0xc4, 0x0f, 0xd5, 0x91, 0xe7, 0x72, 0x17, 0xe5, 0x03, 0xbc, + 0x1a, 0x99, 0xb7, 0x36, 0x4d, 0x97, 0x39, 0x2e, 0x33, 0x04, 0xbc, 0x1f, 0x2c, 0x02, 0xdf, 0xad, + 0x52, 0xdf, 0xed, 0xbb, 0x81, 0xdd, 0x7f, 0x0a, 0xac, 0x3b, 0x3f, 0x6c, 0x40, 0xe6, 0xa5, 0xcb, + 0xf8, 0x2b, 0x97, 0x12, 0xb4, 0x09, 0x19, 0x73, 0x80, 0x6d, 0x6a, 0xd8, 0x96, 0x22, 0x6d, 0x4b, + 0xbb, 0xb7, 0xf5, 0x75, 0xb1, 0xd6, 0x2c, 0xf4, 0x39, 0x20, 0x8a, 0xb9, 0x7d, 0x46, 0x0c, 0xee, + 0x9e, 0x12, 0x6a, 0x58, 0x84, 0xba, 0x8e, 0x92, 0x14, 0x4e, 0x72, 0x80, 0x74, 0x7c, 0xa0, 0xe1, + 0xdb, 0xd1, 0x13, 0x28, 0x5f, 0xf1, 0xb6, 0x7b, 0x66, 0x18, 0x91, 0x12, 0x11, 0xc5, 0x99, 0x08, + 0xad, 0x67, 0x06, 0x41, 0x55, 0x28, 0x72, 0x0f, 0x53, 0xf6, 0x9a, 0x78, 0x86, 0x39, 0xc0, 0x94, + 0x92, 0xa1, 0xbf, 0x91, 0xb4, 0x88, 0x28, 0x44, 0x50, 0x3d, 0x40, 0x34, 0x0b, 0x1d, 0x02, 0xb2, + 0xc8, 0x90, 0xf4, 0x31, 0xb7, 0x5d, 0x6a, 0x60, 0xcb, 0xf2, 0x08, 0x63, 0xca, 0x2d, 0xdf, 0xfd, + 0x40, 0xf9, 0xf0, 0x76, 0xaf, 0x14, 0xa6, 0x5f, 0x0b, 0x90, 0x36, 0xf7, 0x6c, 0xda, 0xd7, 0x0b, + 0xd3, 0x98, 0x10, 0x40, 0xcf, 0x21, 0xe7, 0x91, 0x73, 0xec, 0x59, 0x31, 0xc9, 0xda, 0x12, 0x92, + 0x6c, 0xe0, 0x1f, 0x11, 0xd4, 0x20, 0x6f, 0x91, 0x91, 0xcb, 0x6c, 0x1e, 0x33, 0xac, 0x2f, 0x61, + 0xc8, 0x85, 0x01, 0x11, 0xc5, 0x21, 0x20, 0x8f, 0x58, 0xc4, 0x19, 0x5d, 0x49, 0x26, 0xb3, 0x2c, + 0x99, 0x69, 0x4c, 0x44, 0xf4, 0x35, 0x64, 0xcd, 0x21, 0xb6, 0x9d, 0x98, 0xe3, 0xf6, 0x12, 0x8e, + 0x0d, 0xe1, 0x1e, 0x85, 0x77, 0x61, 0xcb, 0x1d, 0x11, 0x0f, 0x73, 0xd7, 0x8b, 0x18, 0x0c, 0x97, + 0x1a, 0xc1, 0x39, 0x53, 0x60, 0x09, 0xd7, 0xbd, 0x28, 0x36, 0x34, 0x1f, 0xd3, 0xb6, 0x08, 0x44, + 0x47, 0x50, 0x66, 0xf8, 0x35, 0xb9, 0x86, 0xf2, 0xce, 0x12, 0xca, 0xa2, 0x1f, 0x37, 0x4f, 0x47, + 0xa1, 0x34, 0xc4, 0x8c, 0x1b, 0x33, 0x25, 0xf3, 0x30, 0x27, 0xca, 0x86, 0x20, 0xfb, 0xea, 0xdd, + 0xc7, 0x07, 0x89, 0xbf, 0x3e, 0x3e, 0x78, 0xd8, 0xb7, 0xf9, 0x60, 0xdc, 0xab, 0x9a, 0xae, 0x13, + 0x5e, 0x85, 0xf0, 0x67, 0x8f, 0x59, 0xa7, 0xfb, 0xfc, 0xcd, 0x88, 0xb0, 0x6a, 0x83, 0x98, 0x1f, + 0xde, 0xee, 0x41, 0x28, 0xdd, 0x20, 0xa6, 0x8e, 0x7c, 0x66, 0x3d, 0x26, 0xd6, 0x31, 0x27, 0x88, + 0x40, 0x7e, 0x5e, 0x2a, 0xbb, 0x02, 0xa9, 0x9c, 0x77, 0x55, 0x66, 0x08, 0x45, 0xc7, 0xa6, 0x0b, + 0x59, 0xe5, 0x56, 0x20, 0x55, 0x70, 0x6c, 0xaa, 0x2f, 0xaa, 0xe1, 0xc9, 0x82, 0x5a, 0x7e, 0x25, + 0x6a, 0x78, 0x32, 0xa7, 0x76, 0x0e, 0x9b, 0x7e, 0x6e, 0x36, 0xa5, 0xc4, 0x5b, 0xd0, 0x94, 0x57, + 0xa0, 0x59, 0x76, 0x6c, 0xaa, 0xf9, 0xec, 0xd7, 0x08, 0xe3, 0xc9, 0x0d, 0xc2, 0x85, 0x95, 0x08, + 0xe3, 0xc9, 0x75, 0xc2, 0xdf, 0x41, 0xf4, 0xae, 0x21, 0x96, 0xd1, 0xc3, 0x43, 0x4c, 0x4d, 0xa2, + 0x20, 0x21, 0x58, 0xfd, 0x04, 0x41, 0x8d, 0x72, 0x5d, 0x8e, 0x89, 0x0e, 0x02, 0x1e, 0xf4, 0x14, + 0x94, 0x31, 0xed, 0xb9, 0xd4, 0xb2, 0x69, 0xdf, 0x18, 0x11, 0xcf, 0x76, 0x2d, 0x83, 0x11, 0xd3, + 0xa5, 0x16, 0x53, 0x8a, 0xdb, 0xd2, 0x6e, 0x5a, 0x2f, 0xc7, 0xf8, 0x89, 0x80, 0xdb, 0x01, 0x8a, + 0xca, 0xb0, 0x36, 0xc0, 0x43, 0x4e, 0x2c, 0xa5, 0xb4, 0x2d, 0xed, 0x66, 0xf4, 0x70, 0xb5, 0xf3, + 0x87, 0x04, 0x72, 0x23, 0x7e, 0x37, 0xea, 0xc4, 0x74, 0x3d, 0x0b, 0xe5, 0x20, 0x19, 0xce, 0x82, + 0xb4, 0x9e, 0xb4, 0x2d, 0xd4, 0x86, 0x6c, 0xf8, 0x62, 0xc7, 0x8e, 0x3b, 0xa6, 0x3c, 0x98, 0x00, + 0x9f, 0x9c, 0xcf, 0x46, 0x40, 0x52, 0x13, 0x1c, 0xe8, 0x39, 0xac, 0x31, 0x8e, 0xf9, 0x98, 0x89, + 0xe9, 0x90, 0x7b, 0xfc, 0xff, 0xea, 0xdc, 0x58, 0xab, 0xce, 0xef, 0xab, 0x2d, 0xdc, 0xf5, 0x30, + 0x0c, 0xdd, 0x83, 0x75, 0x3e, 0x31, 0x06, 0x98, 0x0d, 0xc2, 0x69, 0xb1, 0xc6, 0x27, 0x2f, 0x31, + 0x1b, 0xec, 0xfc, 0x9e, 0x82, 0x7c, 0x37, 0x2a, 0xc3, 0x0d, 0x29, 0x3d, 0x8b, 0xd5, 0x93, 0x42, + 0xfd, 0xe1, 0x82, 0xfa, 0x1c, 0xc3, 0x9c, 0xf8, 0xb7, 0x90, 0x67, 0x3c, 0x9c, 0x73, 0x61, 0x51, + 0x52, 0xff, 0xaa, 0x28, 0x59, 0xc6, 0xc5, 0x40, 0x0c, 0xab, 0xb2, 0x50, 0xea, 0xf4, 0x0a, 0x4a, + 0xad, 0xc1, 0xff, 0xa6, 0xc7, 0xc6, 0x74, 0x9d, 0xd1, 0x90, 0x88, 0xcb, 0xc0, 0x6d, 0x87, 0xc4, + 0xe7, 0xe7, 0x96, 0xa8, 0x4d, 0x25, 0x76, 0xac, 0xc7, 0x7e, 0x1d, 0xdb, 0x21, 0xd1, 0x39, 0xfa, + 0x02, 0x4a, 0x63, 0x3a, 0x33, 0x80, 0xa3, 0x0e, 0x88, 0xd9, 0xa9, 0xa3, 0x59, 0xac, 0x23, 0xba, + 0x81, 0x9e, 0xc1, 0xfd, 0x80, 0x93, 0x58, 0x61, 0xbd, 0xd8, 0x39, 0x21, 0xa3, 0x38, 0x52, 0xcc, + 0x4c, 0x5d, 0x89, 0x7c, 0x44, 0x31, 0xda, 0xbe, 0x47, 0x10, 0xbf, 0xf3, 0x53, 0x12, 0xe4, 0x99, + 0x3b, 0x16, 0xb4, 0xb3, 0x0a, 0xc5, 0x69, 0x46, 0x9e, 0xb0, 0x19, 0x71, 0x7f, 0x0b, 0xe3, 0xab, + 0xad, 0xd3, 0x2c, 0xb4, 0x05, 0x19, 0xff, 0x25, 0x40, 0x1c, 0xe2, 0x85, 0x9f, 0x2f, 0xf1, 0xfa, + 0x3f, 0xd5, 0xca, 0x9d, 0xdf, 0x24, 0xb8, 0xd3, 0x1e, 0x62, 0x36, 0xb8, 0xe1, 0x5c, 0x23, 0x48, + 0xfb, 0x5d, 0x15, 0x49, 0xa6, 0x75, 0xf1, 0xbc, 0xb8, 0x91, 0xd4, 0x0a, 0xce, 0xd4, 0x67, 0x50, + 0x38, 0xc3, 0x43, 0xdb, 0x9a, 0xfd, 0x66, 0x08, 0xef, 0xa1, 0x1c, 0x03, 0xe1, 0x04, 0x7f, 0xf4, + 0x3d, 0x94, 0xaf, 0xbf, 0xcc, 0x48, 0x81, 0x52, 0x47, 0xaf, 0xb5, 0xda, 0x2f, 0x54, 0xdd, 0xd0, + 0x5a, 0xc6, 0x89, 0x7e, 0x7c, 0xa8, 0xab, 0xed, 0xb6, 0x9c, 0x40, 0x45, 0xc8, 0xc7, 0xc8, 0x8b, + 0x9a, 0xd6, 0x54, 0x1b, 0xb2, 0x84, 0x4a, 0x20, 0x37, 0xd4, 0xa6, 0x7a, 0x58, 0xeb, 0x68, 0xc7, + 0x2d, 0xe3, 0x9b, 0xae, 0xda, 0x55, 0xe5, 0x24, 0xba, 0x07, 0xc5, 0x19, 0x6b, 0xfd, 0xf8, 0xe8, + 0xa4, 0xa9, 0x76, 0x54, 0x39, 0xb5, 0x95, 0xfe, 0xf1, 0xd7, 0x4a, 0xe2, 0xd1, 0x2f, 0x12, 0xdc, + 0xbd, 0xf6, 0x36, 0xa3, 0xfb, 0xa0, 0xd4, 0xea, 0xf5, 0xee, 0x51, 0xb7, 0x59, 0xeb, 0x68, 0xad, + 0x43, 0x43, 0x57, 0x1b, 0xea, 0xd1, 0x89, 0xcf, 0x12, 0xee, 0xa0, 0xdb, 0x3a, 0x38, 0x6e, 0x35, + 0x7c, 0x28, 0xd0, 0x92, 0xd0, 0x26, 0xdc, 0x9d, 0x1a, 0x67, 0x77, 0x9c, 0x44, 0x1b, 0x90, 0x09, + 0x20, 0xb5, 0x21, 0xa7, 0x50, 0x16, 0x6e, 0xd7, 0x9b, 0x35, 0xed, 0xa8, 0x76, 0xd0, 0x54, 0xe5, + 0x34, 0xba, 0x03, 0xeb, 0x62, 0xa9, 0x36, 0xe4, 0x5b, 0xc1, 0xbe, 0x0e, 0x9a, 0xef, 0x2e, 0x2a, + 0xd2, 0xfb, 0x8b, 0x8a, 0xf4, 0xf7, 0x45, 0x45, 0xfa, 0xf9, 0xb2, 0x92, 0x78, 0x7f, 0x59, 0x49, + 0xfc, 0x79, 0x59, 0x49, 0xbc, 0x7a, 0x3c, 0xd3, 0x92, 0xe0, 0xe3, 0x67, 0xaf, 0x89, 0x7b, 0x6c, + 0x3f, 0xfc, 0x63, 0x70, 0xf6, 0xe5, 0xd3, 0xfd, 0xc9, 0xf4, 0xef, 0x81, 0x68, 0x51, 0x6f, 0x4d, + 0x7c, 0xda, 0x3f, 0xf9, 0x27, 0x00, 0x00, 0xff, 0xff, 0x4b, 0x48, 0x0c, 0xc4, 0x3e, 0x0c, 0x00, + 0x00, +} + +func (m *HostZone) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HostZone) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HostZone) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Halted { + i-- + if m.Halted { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa0 + } + if m.UnbondingPeriodSeconds != 0 { + i = encodeVarintStakedym(dAtA, i, uint64(m.UnbondingPeriodSeconds)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x98 + } + { + size := m.DelegatedBalance.Size() + i -= size + if _, err := m.DelegatedBalance.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x92 + { + size := m.MaxInnerRedemptionRate.Size() + i -= size + if _, err := m.MaxInnerRedemptionRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x8a + { + size := m.MinInnerRedemptionRate.Size() + i -= size + if _, err := m.MinInnerRedemptionRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + { + size := m.MaxRedemptionRate.Size() + i -= size + if _, err := m.MaxRedemptionRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x7a + { + size := m.MinRedemptionRate.Size() + i -= size + if _, err := m.MinRedemptionRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x72 + { + size := m.RedemptionRate.Size() + i -= size + if _, err := m.RedemptionRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x6a + { + size := m.LastRedemptionRate.Size() + i -= size + if _, err := m.LastRedemptionRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + if len(m.SafeAddressOnStride) > 0 { + i -= len(m.SafeAddressOnStride) + copy(dAtA[i:], m.SafeAddressOnStride) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.SafeAddressOnStride))) + i-- + dAtA[i] = 0x5a + } + if len(m.OperatorAddressOnStride) > 0 { + i -= len(m.OperatorAddressOnStride) + copy(dAtA[i:], m.OperatorAddressOnStride) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.OperatorAddressOnStride))) + i-- + dAtA[i] = 0x52 + } + if len(m.ClaimAddress) > 0 { + i -= len(m.ClaimAddress) + copy(dAtA[i:], m.ClaimAddress) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.ClaimAddress))) + i-- + dAtA[i] = 0x4a + } + if len(m.RedemptionAddress) > 0 { + i -= len(m.RedemptionAddress) + copy(dAtA[i:], m.RedemptionAddress) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.RedemptionAddress))) + i-- + dAtA[i] = 0x42 + } + if len(m.DepositAddress) > 0 { + i -= len(m.DepositAddress) + copy(dAtA[i:], m.DepositAddress) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.DepositAddress))) + i-- + dAtA[i] = 0x3a + } + if len(m.RewardAddress) > 0 { + i -= len(m.RewardAddress) + copy(dAtA[i:], m.RewardAddress) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.RewardAddress))) + i-- + dAtA[i] = 0x32 + } + if len(m.DelegationAddress) > 0 { + i -= len(m.DelegationAddress) + copy(dAtA[i:], m.DelegationAddress) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.DelegationAddress))) + i-- + dAtA[i] = 0x2a + } + if len(m.TransferChannelId) > 0 { + i -= len(m.TransferChannelId) + copy(dAtA[i:], m.TransferChannelId) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.TransferChannelId))) + i-- + dAtA[i] = 0x22 + } + if len(m.NativeTokenIbcDenom) > 0 { + i -= len(m.NativeTokenIbcDenom) + copy(dAtA[i:], m.NativeTokenIbcDenom) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.NativeTokenIbcDenom))) + i-- + dAtA[i] = 0x1a + } + if len(m.NativeTokenDenom) > 0 { + i -= len(m.NativeTokenDenom) + copy(dAtA[i:], m.NativeTokenDenom) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.NativeTokenDenom))) + i-- + dAtA[i] = 0x12 + } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DelegationRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DelegationRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DelegationRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TxHash) > 0 { + i -= len(m.TxHash) + copy(dAtA[i:], m.TxHash) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.TxHash))) + i-- + dAtA[i] = 0x22 + } + if m.Status != 0 { + i = encodeVarintStakedym(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x18 + } + { + size := m.NativeAmount.Size() + i -= size + if _, err := m.NativeAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.Id != 0 { + i = encodeVarintStakedym(dAtA, i, uint64(m.Id)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *UnbondingRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UnbondingRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UnbondingRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.UnbondedTokenSweepTxHash) > 0 { + i -= len(m.UnbondedTokenSweepTxHash) + copy(dAtA[i:], m.UnbondedTokenSweepTxHash) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.UnbondedTokenSweepTxHash))) + i-- + dAtA[i] = 0x3a + } + if len(m.UndelegationTxHash) > 0 { + i -= len(m.UndelegationTxHash) + copy(dAtA[i:], m.UndelegationTxHash) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.UndelegationTxHash))) + i-- + dAtA[i] = 0x32 + } + if m.UnbondingCompletionTimeSeconds != 0 { + i = encodeVarintStakedym(dAtA, i, uint64(m.UnbondingCompletionTimeSeconds)) + i-- + dAtA[i] = 0x28 + } + { + size := m.NativeAmount.Size() + i -= size + if _, err := m.NativeAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size := m.StTokenAmount.Size() + i -= size + if _, err := m.StTokenAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.Status != 0 { + i = encodeVarintStakedym(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x10 + } + if m.Id != 0 { + i = encodeVarintStakedym(dAtA, i, uint64(m.Id)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *RedemptionRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RedemptionRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RedemptionRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.NativeAmount.Size() + i -= size + if _, err := m.NativeAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size := m.StTokenAmount.Size() + i -= size + if _, err := m.StTokenAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Redeemer) > 0 { + i -= len(m.Redeemer) + copy(dAtA[i:], m.Redeemer) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.Redeemer))) + i-- + dAtA[i] = 0x12 + } + if m.UnbondingRecordId != 0 { + i = encodeVarintStakedym(dAtA, i, uint64(m.UnbondingRecordId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *SlashRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SlashRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SlashRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintStakedym(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0x22 + } + { + size := m.NativeAmount.Size() + i -= size + if _, err := m.NativeAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintStakedym(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.Time != 0 { + i = encodeVarintStakedym(dAtA, i, uint64(m.Time)) + i-- + dAtA[i] = 0x10 + } + if m.Id != 0 { + i = encodeVarintStakedym(dAtA, i, uint64(m.Id)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintStakedym(dAtA []byte, offset int, v uint64) int { + offset -= sovStakedym(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *HostZone) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = len(m.NativeTokenDenom) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = len(m.NativeTokenIbcDenom) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = len(m.TransferChannelId) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = len(m.DelegationAddress) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = len(m.RewardAddress) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = len(m.DepositAddress) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = len(m.RedemptionAddress) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = len(m.ClaimAddress) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = len(m.OperatorAddressOnStride) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = len(m.SafeAddressOnStride) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = m.LastRedemptionRate.Size() + n += 1 + l + sovStakedym(uint64(l)) + l = m.RedemptionRate.Size() + n += 1 + l + sovStakedym(uint64(l)) + l = m.MinRedemptionRate.Size() + n += 1 + l + sovStakedym(uint64(l)) + l = m.MaxRedemptionRate.Size() + n += 1 + l + sovStakedym(uint64(l)) + l = m.MinInnerRedemptionRate.Size() + n += 2 + l + sovStakedym(uint64(l)) + l = m.MaxInnerRedemptionRate.Size() + n += 2 + l + sovStakedym(uint64(l)) + l = m.DelegatedBalance.Size() + n += 2 + l + sovStakedym(uint64(l)) + if m.UnbondingPeriodSeconds != 0 { + n += 2 + sovStakedym(uint64(m.UnbondingPeriodSeconds)) + } + if m.Halted { + n += 3 + } + return n +} + +func (m *DelegationRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Id != 0 { + n += 1 + sovStakedym(uint64(m.Id)) + } + l = m.NativeAmount.Size() + n += 1 + l + sovStakedym(uint64(l)) + if m.Status != 0 { + n += 1 + sovStakedym(uint64(m.Status)) + } + l = len(m.TxHash) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + return n +} + +func (m *UnbondingRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Id != 0 { + n += 1 + sovStakedym(uint64(m.Id)) + } + if m.Status != 0 { + n += 1 + sovStakedym(uint64(m.Status)) + } + l = m.StTokenAmount.Size() + n += 1 + l + sovStakedym(uint64(l)) + l = m.NativeAmount.Size() + n += 1 + l + sovStakedym(uint64(l)) + if m.UnbondingCompletionTimeSeconds != 0 { + n += 1 + sovStakedym(uint64(m.UnbondingCompletionTimeSeconds)) + } + l = len(m.UndelegationTxHash) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = len(m.UnbondedTokenSweepTxHash) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + return n +} + +func (m *RedemptionRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.UnbondingRecordId != 0 { + n += 1 + sovStakedym(uint64(m.UnbondingRecordId)) + } + l = len(m.Redeemer) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + l = m.StTokenAmount.Size() + n += 1 + l + sovStakedym(uint64(l)) + l = m.NativeAmount.Size() + n += 1 + l + sovStakedym(uint64(l)) + return n +} + +func (m *SlashRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Id != 0 { + n += 1 + sovStakedym(uint64(m.Id)) + } + if m.Time != 0 { + n += 1 + sovStakedym(uint64(m.Time)) + } + l = m.NativeAmount.Size() + n += 1 + l + sovStakedym(uint64(l)) + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovStakedym(uint64(l)) + } + return n +} + +func sovStakedym(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozStakedym(x uint64) (n int) { + return sovStakedym(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *HostZone) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HostZone: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HostZone: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NativeTokenDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NativeTokenDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NativeTokenIbcDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NativeTokenIbcDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TransferChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TransferChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegationAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegationAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RewardAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DepositAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DepositAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RedemptionAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RedemptionAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClaimAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClaimAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorAddressOnStride", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OperatorAddressOnStride = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SafeAddressOnStride", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SafeAddressOnStride = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastRedemptionRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.LastRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RedemptionRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.RedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinRedemptionRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxRedemptionRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinInnerRedemptionRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinInnerRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 17: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxInnerRedemptionRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxInnerRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 18: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatedBalance", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.DelegatedBalance.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 19: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingPeriodSeconds", wireType) + } + m.UnbondingPeriodSeconds = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnbondingPeriodSeconds |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 20: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Halted", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Halted = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipStakedym(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthStakedym + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DelegationRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DelegationRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DelegationRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + m.Id = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Id |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NativeAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.NativeAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= DelegationRecordStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStakedym(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthStakedym + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UnbondingRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UnbondingRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UnbondingRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + m.Id = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Id |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= UnbondingRecordStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StTokenAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StTokenAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NativeAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.NativeAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingCompletionTimeSeconds", wireType) + } + m.UnbondingCompletionTimeSeconds = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnbondingCompletionTimeSeconds |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UndelegationTxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UndelegationTxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondedTokenSweepTxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UnbondedTokenSweepTxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStakedym(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthStakedym + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RedemptionRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RedemptionRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RedemptionRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingRecordId", wireType) + } + m.UnbondingRecordId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnbondingRecordId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Redeemer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Redeemer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StTokenAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StTokenAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NativeAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.NativeAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStakedym(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthStakedym + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SlashRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SlashRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SlashRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + m.Id = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Id |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType) + } + m.Time = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Time |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NativeAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.NativeAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStakedym + } + 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 ErrInvalidLengthStakedym + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthStakedym + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipStakedym(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthStakedym + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipStakedym(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStakedym + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStakedym + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowStakedym + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthStakedym + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupStakedym + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthStakedym + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthStakedym = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowStakedym = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupStakedym = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/stakedym/types/tx.pb.go b/x/stakedym/types/tx.pb.go new file mode 100644 index 0000000000..6998300c49 --- /dev/null +++ b/x/stakedym/types/tx.pb.go @@ -0,0 +1,5460 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: stride/stakedym/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type OverwritableRecordType int32 + +const ( + RECORD_TYPE_DELEGATION OverwritableRecordType = 0 + RECORD_TYPE_UNBONDING OverwritableRecordType = 1 + RECORD_TYPE_REDEMPTION OverwritableRecordType = 2 +) + +var OverwritableRecordType_name = map[int32]string{ + 0: "RECORD_TYPE_DELEGATION", + 1: "RECORD_TYPE_UNBONDING", + 2: "RECORD_TYPE_REDEMPTION", +} + +var OverwritableRecordType_value = map[string]int32{ + "RECORD_TYPE_DELEGATION": 0, + "RECORD_TYPE_UNBONDING": 1, + "RECORD_TYPE_REDEMPTION": 2, +} + +func (x OverwritableRecordType) String() string { + return proto.EnumName(OverwritableRecordType_name, int32(x)) +} + +func (OverwritableRecordType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{0} +} + +// LiquidStake +type MsgLiquidStake struct { + Staker string `protobuf:"bytes,1,opt,name=staker,proto3" json:"staker,omitempty"` + NativeAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=native_amount,json=nativeAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"native_amount"` +} + +func (m *MsgLiquidStake) Reset() { *m = MsgLiquidStake{} } +func (m *MsgLiquidStake) String() string { return proto.CompactTextString(m) } +func (*MsgLiquidStake) ProtoMessage() {} +func (*MsgLiquidStake) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{0} +} +func (m *MsgLiquidStake) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgLiquidStake) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgLiquidStake.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgLiquidStake) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgLiquidStake.Merge(m, src) +} +func (m *MsgLiquidStake) XXX_Size() int { + return m.Size() +} +func (m *MsgLiquidStake) XXX_DiscardUnknown() { + xxx_messageInfo_MsgLiquidStake.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgLiquidStake proto.InternalMessageInfo + +func (m *MsgLiquidStake) GetStaker() string { + if m != nil { + return m.Staker + } + return "" +} + +type MsgLiquidStakeResponse struct { + StToken types.Coin `protobuf:"bytes,1,opt,name=st_token,json=stToken,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"st_token"` +} + +func (m *MsgLiquidStakeResponse) Reset() { *m = MsgLiquidStakeResponse{} } +func (m *MsgLiquidStakeResponse) String() string { return proto.CompactTextString(m) } +func (*MsgLiquidStakeResponse) ProtoMessage() {} +func (*MsgLiquidStakeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{1} +} +func (m *MsgLiquidStakeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgLiquidStakeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgLiquidStakeResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgLiquidStakeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgLiquidStakeResponse.Merge(m, src) +} +func (m *MsgLiquidStakeResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgLiquidStakeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgLiquidStakeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgLiquidStakeResponse proto.InternalMessageInfo + +func (m *MsgLiquidStakeResponse) GetStToken() types.Coin { + if m != nil { + return m.StToken + } + return types.Coin{} +} + +// RedeemStake +type MsgRedeemStake struct { + Redeemer string `protobuf:"bytes,1,opt,name=redeemer,proto3" json:"redeemer,omitempty"` + StTokenAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=st_token_amount,json=stTokenAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"st_token_amount"` +} + +func (m *MsgRedeemStake) Reset() { *m = MsgRedeemStake{} } +func (m *MsgRedeemStake) String() string { return proto.CompactTextString(m) } +func (*MsgRedeemStake) ProtoMessage() {} +func (*MsgRedeemStake) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{2} +} +func (m *MsgRedeemStake) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRedeemStake) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRedeemStake.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRedeemStake) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRedeemStake.Merge(m, src) +} +func (m *MsgRedeemStake) XXX_Size() int { + return m.Size() +} +func (m *MsgRedeemStake) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRedeemStake.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRedeemStake proto.InternalMessageInfo + +func (m *MsgRedeemStake) GetRedeemer() string { + if m != nil { + return m.Redeemer + } + return "" +} + +type MsgRedeemStakeResponse struct { + NativeToken types.Coin `protobuf:"bytes,1,opt,name=native_token,json=nativeToken,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"native_token"` +} + +func (m *MsgRedeemStakeResponse) Reset() { *m = MsgRedeemStakeResponse{} } +func (m *MsgRedeemStakeResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRedeemStakeResponse) ProtoMessage() {} +func (*MsgRedeemStakeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{3} +} +func (m *MsgRedeemStakeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRedeemStakeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRedeemStakeResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRedeemStakeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRedeemStakeResponse.Merge(m, src) +} +func (m *MsgRedeemStakeResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRedeemStakeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRedeemStakeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRedeemStakeResponse proto.InternalMessageInfo + +func (m *MsgRedeemStakeResponse) GetNativeToken() types.Coin { + if m != nil { + return m.NativeToken + } + return types.Coin{} +} + +// ConfirmDelegation +type MsgConfirmDelegation struct { + Operator string `protobuf:"bytes,1,opt,name=operator,proto3" json:"operator,omitempty"` + RecordId uint64 `protobuf:"varint,2,opt,name=record_id,json=recordId,proto3" json:"record_id,omitempty"` + TxHash string `protobuf:"bytes,3,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` +} + +func (m *MsgConfirmDelegation) Reset() { *m = MsgConfirmDelegation{} } +func (m *MsgConfirmDelegation) String() string { return proto.CompactTextString(m) } +func (*MsgConfirmDelegation) ProtoMessage() {} +func (*MsgConfirmDelegation) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{4} +} +func (m *MsgConfirmDelegation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgConfirmDelegation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgConfirmDelegation.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgConfirmDelegation) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgConfirmDelegation.Merge(m, src) +} +func (m *MsgConfirmDelegation) XXX_Size() int { + return m.Size() +} +func (m *MsgConfirmDelegation) XXX_DiscardUnknown() { + xxx_messageInfo_MsgConfirmDelegation.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgConfirmDelegation proto.InternalMessageInfo + +func (m *MsgConfirmDelegation) GetOperator() string { + if m != nil { + return m.Operator + } + return "" +} + +func (m *MsgConfirmDelegation) GetRecordId() uint64 { + if m != nil { + return m.RecordId + } + return 0 +} + +func (m *MsgConfirmDelegation) GetTxHash() string { + if m != nil { + return m.TxHash + } + return "" +} + +type MsgConfirmDelegationResponse struct { +} + +func (m *MsgConfirmDelegationResponse) Reset() { *m = MsgConfirmDelegationResponse{} } +func (m *MsgConfirmDelegationResponse) String() string { return proto.CompactTextString(m) } +func (*MsgConfirmDelegationResponse) ProtoMessage() {} +func (*MsgConfirmDelegationResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{5} +} +func (m *MsgConfirmDelegationResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgConfirmDelegationResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgConfirmDelegationResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgConfirmDelegationResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgConfirmDelegationResponse.Merge(m, src) +} +func (m *MsgConfirmDelegationResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgConfirmDelegationResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgConfirmDelegationResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgConfirmDelegationResponse proto.InternalMessageInfo + +// ConfirmUndelegation +type MsgConfirmUndelegation struct { + Operator string `protobuf:"bytes,1,opt,name=operator,proto3" json:"operator,omitempty"` + RecordId uint64 `protobuf:"varint,2,opt,name=record_id,json=recordId,proto3" json:"record_id,omitempty"` + TxHash string `protobuf:"bytes,3,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` +} + +func (m *MsgConfirmUndelegation) Reset() { *m = MsgConfirmUndelegation{} } +func (m *MsgConfirmUndelegation) String() string { return proto.CompactTextString(m) } +func (*MsgConfirmUndelegation) ProtoMessage() {} +func (*MsgConfirmUndelegation) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{6} +} +func (m *MsgConfirmUndelegation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgConfirmUndelegation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgConfirmUndelegation.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgConfirmUndelegation) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgConfirmUndelegation.Merge(m, src) +} +func (m *MsgConfirmUndelegation) XXX_Size() int { + return m.Size() +} +func (m *MsgConfirmUndelegation) XXX_DiscardUnknown() { + xxx_messageInfo_MsgConfirmUndelegation.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgConfirmUndelegation proto.InternalMessageInfo + +func (m *MsgConfirmUndelegation) GetOperator() string { + if m != nil { + return m.Operator + } + return "" +} + +func (m *MsgConfirmUndelegation) GetRecordId() uint64 { + if m != nil { + return m.RecordId + } + return 0 +} + +func (m *MsgConfirmUndelegation) GetTxHash() string { + if m != nil { + return m.TxHash + } + return "" +} + +type MsgConfirmUndelegationResponse struct { +} + +func (m *MsgConfirmUndelegationResponse) Reset() { *m = MsgConfirmUndelegationResponse{} } +func (m *MsgConfirmUndelegationResponse) String() string { return proto.CompactTextString(m) } +func (*MsgConfirmUndelegationResponse) ProtoMessage() {} +func (*MsgConfirmUndelegationResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{7} +} +func (m *MsgConfirmUndelegationResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgConfirmUndelegationResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgConfirmUndelegationResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgConfirmUndelegationResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgConfirmUndelegationResponse.Merge(m, src) +} +func (m *MsgConfirmUndelegationResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgConfirmUndelegationResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgConfirmUndelegationResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgConfirmUndelegationResponse proto.InternalMessageInfo + +// ConfirmUnbondedTokenSweep +type MsgConfirmUnbondedTokenSweep struct { + Operator string `protobuf:"bytes,1,opt,name=operator,proto3" json:"operator,omitempty"` + RecordId uint64 `protobuf:"varint,2,opt,name=record_id,json=recordId,proto3" json:"record_id,omitempty"` + TxHash string `protobuf:"bytes,3,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` +} + +func (m *MsgConfirmUnbondedTokenSweep) Reset() { *m = MsgConfirmUnbondedTokenSweep{} } +func (m *MsgConfirmUnbondedTokenSweep) String() string { return proto.CompactTextString(m) } +func (*MsgConfirmUnbondedTokenSweep) ProtoMessage() {} +func (*MsgConfirmUnbondedTokenSweep) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{8} +} +func (m *MsgConfirmUnbondedTokenSweep) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgConfirmUnbondedTokenSweep) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgConfirmUnbondedTokenSweep.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgConfirmUnbondedTokenSweep) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgConfirmUnbondedTokenSweep.Merge(m, src) +} +func (m *MsgConfirmUnbondedTokenSweep) XXX_Size() int { + return m.Size() +} +func (m *MsgConfirmUnbondedTokenSweep) XXX_DiscardUnknown() { + xxx_messageInfo_MsgConfirmUnbondedTokenSweep.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgConfirmUnbondedTokenSweep proto.InternalMessageInfo + +func (m *MsgConfirmUnbondedTokenSweep) GetOperator() string { + if m != nil { + return m.Operator + } + return "" +} + +func (m *MsgConfirmUnbondedTokenSweep) GetRecordId() uint64 { + if m != nil { + return m.RecordId + } + return 0 +} + +func (m *MsgConfirmUnbondedTokenSweep) GetTxHash() string { + if m != nil { + return m.TxHash + } + return "" +} + +type MsgConfirmUnbondedTokenSweepResponse struct { +} + +func (m *MsgConfirmUnbondedTokenSweepResponse) Reset() { *m = MsgConfirmUnbondedTokenSweepResponse{} } +func (m *MsgConfirmUnbondedTokenSweepResponse) String() string { return proto.CompactTextString(m) } +func (*MsgConfirmUnbondedTokenSweepResponse) ProtoMessage() {} +func (*MsgConfirmUnbondedTokenSweepResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{9} +} +func (m *MsgConfirmUnbondedTokenSweepResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgConfirmUnbondedTokenSweepResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgConfirmUnbondedTokenSweepResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgConfirmUnbondedTokenSweepResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgConfirmUnbondedTokenSweepResponse.Merge(m, src) +} +func (m *MsgConfirmUnbondedTokenSweepResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgConfirmUnbondedTokenSweepResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgConfirmUnbondedTokenSweepResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgConfirmUnbondedTokenSweepResponse proto.InternalMessageInfo + +// AdjustDelegatedBalance +type MsgAdjustDelegatedBalance struct { + Operator string `protobuf:"bytes,1,opt,name=operator,proto3" json:"operator,omitempty"` + DelegationOffset github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=delegation_offset,json=delegationOffset,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"delegation_offset"` + ValidatorAddress string `protobuf:"bytes,3,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"` +} + +func (m *MsgAdjustDelegatedBalance) Reset() { *m = MsgAdjustDelegatedBalance{} } +func (m *MsgAdjustDelegatedBalance) String() string { return proto.CompactTextString(m) } +func (*MsgAdjustDelegatedBalance) ProtoMessage() {} +func (*MsgAdjustDelegatedBalance) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{10} +} +func (m *MsgAdjustDelegatedBalance) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAdjustDelegatedBalance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAdjustDelegatedBalance.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgAdjustDelegatedBalance) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAdjustDelegatedBalance.Merge(m, src) +} +func (m *MsgAdjustDelegatedBalance) XXX_Size() int { + return m.Size() +} +func (m *MsgAdjustDelegatedBalance) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAdjustDelegatedBalance.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAdjustDelegatedBalance proto.InternalMessageInfo + +func (m *MsgAdjustDelegatedBalance) GetOperator() string { + if m != nil { + return m.Operator + } + return "" +} + +func (m *MsgAdjustDelegatedBalance) GetValidatorAddress() string { + if m != nil { + return m.ValidatorAddress + } + return "" +} + +type MsgAdjustDelegatedBalanceResponse struct { +} + +func (m *MsgAdjustDelegatedBalanceResponse) Reset() { *m = MsgAdjustDelegatedBalanceResponse{} } +func (m *MsgAdjustDelegatedBalanceResponse) String() string { return proto.CompactTextString(m) } +func (*MsgAdjustDelegatedBalanceResponse) ProtoMessage() {} +func (*MsgAdjustDelegatedBalanceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{11} +} +func (m *MsgAdjustDelegatedBalanceResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAdjustDelegatedBalanceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAdjustDelegatedBalanceResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgAdjustDelegatedBalanceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAdjustDelegatedBalanceResponse.Merge(m, src) +} +func (m *MsgAdjustDelegatedBalanceResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgAdjustDelegatedBalanceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAdjustDelegatedBalanceResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAdjustDelegatedBalanceResponse proto.InternalMessageInfo + +// UpdateInnerRedemptionRate +type MsgUpdateInnerRedemptionRateBounds struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + MinInnerRedemptionRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=min_inner_redemption_rate,json=minInnerRedemptionRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"min_inner_redemption_rate"` + MaxInnerRedemptionRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=max_inner_redemption_rate,json=maxInnerRedemptionRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"max_inner_redemption_rate"` +} + +func (m *MsgUpdateInnerRedemptionRateBounds) Reset() { *m = MsgUpdateInnerRedemptionRateBounds{} } +func (m *MsgUpdateInnerRedemptionRateBounds) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateInnerRedemptionRateBounds) ProtoMessage() {} +func (*MsgUpdateInnerRedemptionRateBounds) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{12} +} +func (m *MsgUpdateInnerRedemptionRateBounds) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateInnerRedemptionRateBounds) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateInnerRedemptionRateBounds.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateInnerRedemptionRateBounds) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateInnerRedemptionRateBounds.Merge(m, src) +} +func (m *MsgUpdateInnerRedemptionRateBounds) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateInnerRedemptionRateBounds) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateInnerRedemptionRateBounds.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateInnerRedemptionRateBounds proto.InternalMessageInfo + +func (m *MsgUpdateInnerRedemptionRateBounds) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +type MsgUpdateInnerRedemptionRateBoundsResponse struct { +} + +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) Reset() { + *m = MsgUpdateInnerRedemptionRateBoundsResponse{} +} +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) String() string { + return proto.CompactTextString(m) +} +func (*MsgUpdateInnerRedemptionRateBoundsResponse) ProtoMessage() {} +func (*MsgUpdateInnerRedemptionRateBoundsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{13} +} +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateInnerRedemptionRateBoundsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateInnerRedemptionRateBoundsResponse.Merge(m, src) +} +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateInnerRedemptionRateBoundsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateInnerRedemptionRateBoundsResponse proto.InternalMessageInfo + +// ResumeHostZone +type MsgResumeHostZone struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` +} + +func (m *MsgResumeHostZone) Reset() { *m = MsgResumeHostZone{} } +func (m *MsgResumeHostZone) String() string { return proto.CompactTextString(m) } +func (*MsgResumeHostZone) ProtoMessage() {} +func (*MsgResumeHostZone) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{14} +} +func (m *MsgResumeHostZone) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgResumeHostZone) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgResumeHostZone.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgResumeHostZone) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgResumeHostZone.Merge(m, src) +} +func (m *MsgResumeHostZone) XXX_Size() int { + return m.Size() +} +func (m *MsgResumeHostZone) XXX_DiscardUnknown() { + xxx_messageInfo_MsgResumeHostZone.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgResumeHostZone proto.InternalMessageInfo + +func (m *MsgResumeHostZone) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +type MsgResumeHostZoneResponse struct { +} + +func (m *MsgResumeHostZoneResponse) Reset() { *m = MsgResumeHostZoneResponse{} } +func (m *MsgResumeHostZoneResponse) String() string { return proto.CompactTextString(m) } +func (*MsgResumeHostZoneResponse) ProtoMessage() {} +func (*MsgResumeHostZoneResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{15} +} +func (m *MsgResumeHostZoneResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgResumeHostZoneResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgResumeHostZoneResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgResumeHostZoneResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgResumeHostZoneResponse.Merge(m, src) +} +func (m *MsgResumeHostZoneResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgResumeHostZoneResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgResumeHostZoneResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgResumeHostZoneResponse proto.InternalMessageInfo + +// RefreshRedemptionRate +type MsgRefreshRedemptionRate struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` +} + +func (m *MsgRefreshRedemptionRate) Reset() { *m = MsgRefreshRedemptionRate{} } +func (m *MsgRefreshRedemptionRate) String() string { return proto.CompactTextString(m) } +func (*MsgRefreshRedemptionRate) ProtoMessage() {} +func (*MsgRefreshRedemptionRate) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{16} +} +func (m *MsgRefreshRedemptionRate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRefreshRedemptionRate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRefreshRedemptionRate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRefreshRedemptionRate) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRefreshRedemptionRate.Merge(m, src) +} +func (m *MsgRefreshRedemptionRate) XXX_Size() int { + return m.Size() +} +func (m *MsgRefreshRedemptionRate) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRefreshRedemptionRate.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRefreshRedemptionRate proto.InternalMessageInfo + +func (m *MsgRefreshRedemptionRate) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +type MsgRefreshRedemptionRateResponse struct { +} + +func (m *MsgRefreshRedemptionRateResponse) Reset() { *m = MsgRefreshRedemptionRateResponse{} } +func (m *MsgRefreshRedemptionRateResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRefreshRedemptionRateResponse) ProtoMessage() {} +func (*MsgRefreshRedemptionRateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{17} +} +func (m *MsgRefreshRedemptionRateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRefreshRedemptionRateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRefreshRedemptionRateResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRefreshRedemptionRateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRefreshRedemptionRateResponse.Merge(m, src) +} +func (m *MsgRefreshRedemptionRateResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRefreshRedemptionRateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRefreshRedemptionRateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRefreshRedemptionRateResponse proto.InternalMessageInfo + +// OverwriteDelegationRecord +type MsgOverwriteDelegationRecord struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + DelegationRecord *DelegationRecord `protobuf:"bytes,2,opt,name=delegation_record,json=delegationRecord,proto3" json:"delegation_record,omitempty"` +} + +func (m *MsgOverwriteDelegationRecord) Reset() { *m = MsgOverwriteDelegationRecord{} } +func (m *MsgOverwriteDelegationRecord) String() string { return proto.CompactTextString(m) } +func (*MsgOverwriteDelegationRecord) ProtoMessage() {} +func (*MsgOverwriteDelegationRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{18} +} +func (m *MsgOverwriteDelegationRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOverwriteDelegationRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOverwriteDelegationRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgOverwriteDelegationRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOverwriteDelegationRecord.Merge(m, src) +} +func (m *MsgOverwriteDelegationRecord) XXX_Size() int { + return m.Size() +} +func (m *MsgOverwriteDelegationRecord) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOverwriteDelegationRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOverwriteDelegationRecord proto.InternalMessageInfo + +func (m *MsgOverwriteDelegationRecord) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgOverwriteDelegationRecord) GetDelegationRecord() *DelegationRecord { + if m != nil { + return m.DelegationRecord + } + return nil +} + +type MsgOverwriteDelegationRecordResponse struct { +} + +func (m *MsgOverwriteDelegationRecordResponse) Reset() { *m = MsgOverwriteDelegationRecordResponse{} } +func (m *MsgOverwriteDelegationRecordResponse) String() string { return proto.CompactTextString(m) } +func (*MsgOverwriteDelegationRecordResponse) ProtoMessage() {} +func (*MsgOverwriteDelegationRecordResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{19} +} +func (m *MsgOverwriteDelegationRecordResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOverwriteDelegationRecordResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOverwriteDelegationRecordResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgOverwriteDelegationRecordResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOverwriteDelegationRecordResponse.Merge(m, src) +} +func (m *MsgOverwriteDelegationRecordResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgOverwriteDelegationRecordResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOverwriteDelegationRecordResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOverwriteDelegationRecordResponse proto.InternalMessageInfo + +// OverwriteUnbondingRecord +type MsgOverwriteUnbondingRecord struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + UnbondingRecord *UnbondingRecord `protobuf:"bytes,2,opt,name=unbonding_record,json=unbondingRecord,proto3" json:"unbonding_record,omitempty"` +} + +func (m *MsgOverwriteUnbondingRecord) Reset() { *m = MsgOverwriteUnbondingRecord{} } +func (m *MsgOverwriteUnbondingRecord) String() string { return proto.CompactTextString(m) } +func (*MsgOverwriteUnbondingRecord) ProtoMessage() {} +func (*MsgOverwriteUnbondingRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{20} +} +func (m *MsgOverwriteUnbondingRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOverwriteUnbondingRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOverwriteUnbondingRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgOverwriteUnbondingRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOverwriteUnbondingRecord.Merge(m, src) +} +func (m *MsgOverwriteUnbondingRecord) XXX_Size() int { + return m.Size() +} +func (m *MsgOverwriteUnbondingRecord) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOverwriteUnbondingRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOverwriteUnbondingRecord proto.InternalMessageInfo + +func (m *MsgOverwriteUnbondingRecord) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgOverwriteUnbondingRecord) GetUnbondingRecord() *UnbondingRecord { + if m != nil { + return m.UnbondingRecord + } + return nil +} + +type MsgOverwriteUnbondingRecordResponse struct { +} + +func (m *MsgOverwriteUnbondingRecordResponse) Reset() { *m = MsgOverwriteUnbondingRecordResponse{} } +func (m *MsgOverwriteUnbondingRecordResponse) String() string { return proto.CompactTextString(m) } +func (*MsgOverwriteUnbondingRecordResponse) ProtoMessage() {} +func (*MsgOverwriteUnbondingRecordResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{21} +} +func (m *MsgOverwriteUnbondingRecordResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOverwriteUnbondingRecordResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOverwriteUnbondingRecordResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgOverwriteUnbondingRecordResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOverwriteUnbondingRecordResponse.Merge(m, src) +} +func (m *MsgOverwriteUnbondingRecordResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgOverwriteUnbondingRecordResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOverwriteUnbondingRecordResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOverwriteUnbondingRecordResponse proto.InternalMessageInfo + +// OverwriteRedemptionRecord +type MsgOverwriteRedemptionRecord struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + RedemptionRecord *RedemptionRecord `protobuf:"bytes,2,opt,name=redemption_record,json=redemptionRecord,proto3" json:"redemption_record,omitempty"` +} + +func (m *MsgOverwriteRedemptionRecord) Reset() { *m = MsgOverwriteRedemptionRecord{} } +func (m *MsgOverwriteRedemptionRecord) String() string { return proto.CompactTextString(m) } +func (*MsgOverwriteRedemptionRecord) ProtoMessage() {} +func (*MsgOverwriteRedemptionRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{22} +} +func (m *MsgOverwriteRedemptionRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOverwriteRedemptionRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOverwriteRedemptionRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgOverwriteRedemptionRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOverwriteRedemptionRecord.Merge(m, src) +} +func (m *MsgOverwriteRedemptionRecord) XXX_Size() int { + return m.Size() +} +func (m *MsgOverwriteRedemptionRecord) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOverwriteRedemptionRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOverwriteRedemptionRecord proto.InternalMessageInfo + +func (m *MsgOverwriteRedemptionRecord) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgOverwriteRedemptionRecord) GetRedemptionRecord() *RedemptionRecord { + if m != nil { + return m.RedemptionRecord + } + return nil +} + +type MsgOverwriteRedemptionRecordResponse struct { +} + +func (m *MsgOverwriteRedemptionRecordResponse) Reset() { *m = MsgOverwriteRedemptionRecordResponse{} } +func (m *MsgOverwriteRedemptionRecordResponse) String() string { return proto.CompactTextString(m) } +func (*MsgOverwriteRedemptionRecordResponse) ProtoMessage() {} +func (*MsgOverwriteRedemptionRecordResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{23} +} +func (m *MsgOverwriteRedemptionRecordResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOverwriteRedemptionRecordResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOverwriteRedemptionRecordResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgOverwriteRedemptionRecordResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOverwriteRedemptionRecordResponse.Merge(m, src) +} +func (m *MsgOverwriteRedemptionRecordResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgOverwriteRedemptionRecordResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOverwriteRedemptionRecordResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOverwriteRedemptionRecordResponse proto.InternalMessageInfo + +// SetOperatorAddress +type MsgSetOperatorAddress struct { + Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` + Operator string `protobuf:"bytes,2,opt,name=operator,proto3" json:"operator,omitempty"` +} + +func (m *MsgSetOperatorAddress) Reset() { *m = MsgSetOperatorAddress{} } +func (m *MsgSetOperatorAddress) String() string { return proto.CompactTextString(m) } +func (*MsgSetOperatorAddress) ProtoMessage() {} +func (*MsgSetOperatorAddress) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{24} +} +func (m *MsgSetOperatorAddress) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSetOperatorAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSetOperatorAddress.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSetOperatorAddress) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSetOperatorAddress.Merge(m, src) +} +func (m *MsgSetOperatorAddress) XXX_Size() int { + return m.Size() +} +func (m *MsgSetOperatorAddress) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSetOperatorAddress.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSetOperatorAddress proto.InternalMessageInfo + +func (m *MsgSetOperatorAddress) GetSigner() string { + if m != nil { + return m.Signer + } + return "" +} + +func (m *MsgSetOperatorAddress) GetOperator() string { + if m != nil { + return m.Operator + } + return "" +} + +type MsgSetOperatorAddressResponse struct { +} + +func (m *MsgSetOperatorAddressResponse) Reset() { *m = MsgSetOperatorAddressResponse{} } +func (m *MsgSetOperatorAddressResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSetOperatorAddressResponse) ProtoMessage() {} +func (*MsgSetOperatorAddressResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_85c52040fb1554a8, []int{25} +} +func (m *MsgSetOperatorAddressResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSetOperatorAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSetOperatorAddressResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSetOperatorAddressResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSetOperatorAddressResponse.Merge(m, src) +} +func (m *MsgSetOperatorAddressResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSetOperatorAddressResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSetOperatorAddressResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSetOperatorAddressResponse proto.InternalMessageInfo + +func init() { + proto.RegisterEnum("stride.stakedym.OverwritableRecordType", OverwritableRecordType_name, OverwritableRecordType_value) + proto.RegisterType((*MsgLiquidStake)(nil), "stride.stakedym.MsgLiquidStake") + proto.RegisterType((*MsgLiquidStakeResponse)(nil), "stride.stakedym.MsgLiquidStakeResponse") + proto.RegisterType((*MsgRedeemStake)(nil), "stride.stakedym.MsgRedeemStake") + proto.RegisterType((*MsgRedeemStakeResponse)(nil), "stride.stakedym.MsgRedeemStakeResponse") + proto.RegisterType((*MsgConfirmDelegation)(nil), "stride.stakedym.MsgConfirmDelegation") + proto.RegisterType((*MsgConfirmDelegationResponse)(nil), "stride.stakedym.MsgConfirmDelegationResponse") + proto.RegisterType((*MsgConfirmUndelegation)(nil), "stride.stakedym.MsgConfirmUndelegation") + proto.RegisterType((*MsgConfirmUndelegationResponse)(nil), "stride.stakedym.MsgConfirmUndelegationResponse") + proto.RegisterType((*MsgConfirmUnbondedTokenSweep)(nil), "stride.stakedym.MsgConfirmUnbondedTokenSweep") + proto.RegisterType((*MsgConfirmUnbondedTokenSweepResponse)(nil), "stride.stakedym.MsgConfirmUnbondedTokenSweepResponse") + proto.RegisterType((*MsgAdjustDelegatedBalance)(nil), "stride.stakedym.MsgAdjustDelegatedBalance") + proto.RegisterType((*MsgAdjustDelegatedBalanceResponse)(nil), "stride.stakedym.MsgAdjustDelegatedBalanceResponse") + proto.RegisterType((*MsgUpdateInnerRedemptionRateBounds)(nil), "stride.stakedym.MsgUpdateInnerRedemptionRateBounds") + proto.RegisterType((*MsgUpdateInnerRedemptionRateBoundsResponse)(nil), "stride.stakedym.MsgUpdateInnerRedemptionRateBoundsResponse") + proto.RegisterType((*MsgResumeHostZone)(nil), "stride.stakedym.MsgResumeHostZone") + proto.RegisterType((*MsgResumeHostZoneResponse)(nil), "stride.stakedym.MsgResumeHostZoneResponse") + proto.RegisterType((*MsgRefreshRedemptionRate)(nil), "stride.stakedym.MsgRefreshRedemptionRate") + proto.RegisterType((*MsgRefreshRedemptionRateResponse)(nil), "stride.stakedym.MsgRefreshRedemptionRateResponse") + proto.RegisterType((*MsgOverwriteDelegationRecord)(nil), "stride.stakedym.MsgOverwriteDelegationRecord") + proto.RegisterType((*MsgOverwriteDelegationRecordResponse)(nil), "stride.stakedym.MsgOverwriteDelegationRecordResponse") + proto.RegisterType((*MsgOverwriteUnbondingRecord)(nil), "stride.stakedym.MsgOverwriteUnbondingRecord") + proto.RegisterType((*MsgOverwriteUnbondingRecordResponse)(nil), "stride.stakedym.MsgOverwriteUnbondingRecordResponse") + proto.RegisterType((*MsgOverwriteRedemptionRecord)(nil), "stride.stakedym.MsgOverwriteRedemptionRecord") + proto.RegisterType((*MsgOverwriteRedemptionRecordResponse)(nil), "stride.stakedym.MsgOverwriteRedemptionRecordResponse") + proto.RegisterType((*MsgSetOperatorAddress)(nil), "stride.stakedym.MsgSetOperatorAddress") + proto.RegisterType((*MsgSetOperatorAddressResponse)(nil), "stride.stakedym.MsgSetOperatorAddressResponse") +} + +func init() { proto.RegisterFile("stride/stakedym/tx.proto", fileDescriptor_85c52040fb1554a8) } + +var fileDescriptor_85c52040fb1554a8 = []byte{ + // 1354 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcf, 0x93, 0x13, 0x45, + 0x14, 0xde, 0x59, 0x28, 0x7e, 0x74, 0x04, 0xb2, 0x23, 0x84, 0x64, 0x90, 0x64, 0x19, 0x60, 0x81, + 0xc0, 0xce, 0x98, 0x00, 0x6a, 0x45, 0x2f, 0x1b, 0x92, 0x82, 0x2d, 0x37, 0x1b, 0x2a, 0xbb, 0x2b, + 0x25, 0x1e, 0xc6, 0x49, 0xa6, 0x77, 0x32, 0xb2, 0x33, 0x1d, 0xa6, 0x3b, 0x21, 0x94, 0x55, 0x96, + 0x7a, 0xa2, 0x3c, 0x59, 0xe5, 0xc9, 0x83, 0x27, 0xab, 0xac, 0xd2, 0x8b, 0x1c, 0xbc, 0x79, 0xf1, + 0xc8, 0x91, 0xf2, 0x64, 0x79, 0x40, 0x0b, 0x0e, 0x94, 0xff, 0x80, 0x5e, 0xad, 0xf9, 0x49, 0xcf, + 0x4c, 0x4f, 0x12, 0x50, 0x2e, 0x9b, 0x4c, 0xbf, 0xaf, 0xdf, 0xfb, 0xde, 0xf7, 0x7a, 0x5e, 0xbf, + 0x0d, 0xc8, 0x63, 0x62, 0x1b, 0x1a, 0x94, 0x31, 0x51, 0x6f, 0x41, 0xed, 0xae, 0x29, 0x93, 0xb1, + 0x34, 0xb0, 0x11, 0x41, 0xfc, 0x21, 0xcf, 0x22, 0x05, 0x16, 0xe1, 0x68, 0x0f, 0x61, 0x13, 0x61, + 0xd9, 0xc4, 0xba, 0x3c, 0xaa, 0x38, 0x1f, 0x1e, 0x52, 0x58, 0x50, 0x4d, 0xc3, 0x42, 0xb2, 0xfb, + 0xd7, 0x5f, 0x3a, 0xac, 0x23, 0x1d, 0xb9, 0x5f, 0x65, 0xe7, 0x9b, 0xbf, 0x5a, 0xf4, 0x3d, 0x74, + 0x55, 0x0c, 0xe5, 0x51, 0xa5, 0x0b, 0x89, 0x5a, 0x91, 0x7b, 0xc8, 0xb0, 0x7c, 0x7b, 0xc1, 0xb3, + 0x2b, 0xde, 0x46, 0xef, 0x21, 0xd8, 0x1a, 0xe7, 0x19, 0x7c, 0xf1, 0xec, 0xe2, 0x77, 0x1c, 0x38, + 0xd8, 0xc2, 0xfa, 0x9a, 0x71, 0x7b, 0x68, 0x68, 0x1b, 0x8e, 0x8d, 0xcf, 0x81, 0x3d, 0x2e, 0xc8, + 0xce, 0x73, 0x8b, 0xdc, 0xd9, 0xfd, 0x1d, 0xff, 0x89, 0xdf, 0x00, 0x07, 0x2c, 0x95, 0x18, 0x23, + 0xa8, 0xa8, 0x26, 0x1a, 0x5a, 0x24, 0x3f, 0xef, 0x98, 0xeb, 0xd2, 0x83, 0x47, 0xa5, 0xb9, 0xdf, + 0x1f, 0x95, 0x96, 0x74, 0x83, 0xf4, 0x87, 0x5d, 0xa9, 0x87, 0x4c, 0x9f, 0x82, 0xff, 0xb1, 0x8c, + 0xb5, 0x5b, 0x32, 0xb9, 0x3b, 0x80, 0x58, 0x5a, 0xb5, 0x48, 0xe7, 0x15, 0xcf, 0xc9, 0x8a, 0xeb, + 0xa3, 0x76, 0xe6, 0xf3, 0xa7, 0xf7, 0xcb, 0x7e, 0x84, 0x2f, 0x9e, 0xde, 0x2f, 0x1f, 0x0d, 0x89, + 0x46, 0x59, 0x89, 0x9f, 0x72, 0x20, 0x17, 0x5d, 0xea, 0x40, 0x3c, 0x40, 0x16, 0x86, 0xfc, 0x36, + 0xd8, 0x87, 0x89, 0x42, 0xd0, 0x2d, 0x68, 0xb9, 0x94, 0x33, 0xd5, 0x82, 0xe4, 0x8b, 0xe0, 0x28, + 0x26, 0xf9, 0x8a, 0x49, 0x57, 0x90, 0x61, 0xd5, 0x5f, 0x77, 0xe8, 0xfe, 0xf0, 0x47, 0xe9, 0xec, + 0x0c, 0x74, 0x9d, 0x0d, 0xb8, 0xb3, 0x17, 0x93, 0x4d, 0xc7, 0xb7, 0xf8, 0xa3, 0xa7, 0x55, 0x07, + 0x6a, 0x10, 0x9a, 0x9e, 0x56, 0x02, 0xd8, 0x67, 0xbb, 0x8f, 0xa1, 0x5a, 0xe1, 0x33, 0xff, 0x1e, + 0x38, 0x14, 0xd0, 0xfa, 0x6f, 0x8a, 0x1d, 0xf0, 0x09, 0xf8, 0x92, 0x9d, 0x73, 0x24, 0x0b, 0xc3, + 0x24, 0x44, 0xa3, 0xe8, 0x89, 0xf7, 0x3c, 0xd1, 0xa8, 0xa5, 0x50, 0x34, 0x0b, 0xf8, 0x85, 0x78, + 0x79, 0xc2, 0x65, 0xbc, 0x00, 0x9e, 0x78, 0x5f, 0x73, 0xe0, 0x70, 0x0b, 0xeb, 0x57, 0x90, 0xb5, + 0x6d, 0xd8, 0x66, 0x03, 0xee, 0x40, 0x5d, 0x25, 0x06, 0xb2, 0x1c, 0x09, 0xd1, 0x00, 0xda, 0x2a, + 0x41, 0xa1, 0x84, 0xc1, 0x33, 0x7f, 0x0c, 0xec, 0xb7, 0x61, 0x0f, 0xd9, 0x9a, 0x62, 0x68, 0xae, + 0x78, 0xbb, 0x1d, 0x7d, 0x9d, 0x85, 0x55, 0x8d, 0x3f, 0x0a, 0xf6, 0x92, 0xb1, 0xd2, 0x57, 0x71, + 0x3f, 0xbf, 0xcb, 0x3b, 0xa8, 0x64, 0x7c, 0x4d, 0xc5, 0xfd, 0x9a, 0xec, 0x0a, 0x14, 0x38, 0x71, + 0x04, 0x3a, 0x4e, 0x0b, 0x94, 0xa0, 0x20, 0x16, 0xc1, 0x6b, 0xac, 0xf5, 0x40, 0x2b, 0xf1, 0x1b, + 0x4f, 0x46, 0x1f, 0xb0, 0x65, 0x69, 0x2f, 0x93, 0x7d, 0x25, 0xc1, 0xbe, 0xc4, 0x60, 0x4f, 0x93, + 0x10, 0x17, 0x41, 0x91, 0x6d, 0x09, 0x33, 0xf8, 0x9e, 0xa3, 0x53, 0xdc, 0xb2, 0xba, 0xc8, 0xd2, + 0xa0, 0xe6, 0x56, 0x66, 0xe3, 0x0e, 0x84, 0x83, 0x97, 0x90, 0xc7, 0x9b, 0x89, 0x3c, 0x4e, 0x33, + 0xf3, 0x88, 0x53, 0x11, 0x97, 0xc0, 0xa9, 0x49, 0xf6, 0x30, 0xa7, 0x7f, 0x38, 0x50, 0x68, 0x61, + 0x7d, 0x45, 0xfb, 0x68, 0x88, 0x89, 0x5f, 0x35, 0xa8, 0xd5, 0xd5, 0x1d, 0xd5, 0xea, 0xc1, 0x89, + 0x09, 0x7d, 0x00, 0x16, 0x9e, 0x69, 0xa4, 0xa0, 0xed, 0x6d, 0x0c, 0x5f, 0xf4, 0xdd, 0xcc, 0x3e, + 0x73, 0xd4, 0x76, 0xfd, 0xf0, 0xe7, 0xc1, 0xc2, 0x48, 0xdd, 0x31, 0x34, 0x27, 0x92, 0xa2, 0x6a, + 0x9a, 0x0d, 0x31, 0xf6, 0xa5, 0xc9, 0x86, 0x86, 0x15, 0x6f, 0xbd, 0x76, 0x29, 0x21, 0x92, 0x48, + 0x8b, 0xc4, 0xce, 0x4d, 0x3c, 0x09, 0x4e, 0xa4, 0x1a, 0x43, 0x79, 0xfe, 0x9a, 0x07, 0x62, 0x0b, + 0xeb, 0x5b, 0x03, 0x4d, 0x25, 0x70, 0xd5, 0xb2, 0xa0, 0xed, 0xb4, 0x01, 0x73, 0xe0, 0x9e, 0x0b, + 0x95, 0xc0, 0x3a, 0x1a, 0x5a, 0x1a, 0xe6, 0xf3, 0x60, 0x6f, 0xcf, 0x86, 0x94, 0x4c, 0xc1, 0x23, + 0x7f, 0x07, 0x14, 0x4c, 0xc3, 0x52, 0x0c, 0x67, 0xab, 0x62, 0x87, 0x7b, 0x15, 0x5b, 0x25, 0xd0, + 0x57, 0xeb, 0x9d, 0xe7, 0x50, 0xab, 0x01, 0x7b, 0xbf, 0xfe, 0xb4, 0x0c, 0xfc, 0xfe, 0xd2, 0x80, + 0xbd, 0x4e, 0xce, 0x34, 0x2c, 0x06, 0x31, 0x37, 0xb0, 0x3a, 0x4e, 0x09, 0xbc, 0xeb, 0x7f, 0x09, + 0xac, 0x8e, 0x19, 0x81, 0xbd, 0x23, 0x1b, 0xe4, 0xef, 0x14, 0x63, 0x89, 0x2e, 0x86, 0xa7, 0x24, + 0x4b, 0x44, 0xf1, 0x02, 0x28, 0x4f, 0x97, 0x3a, 0xac, 0xcc, 0x4d, 0xb0, 0xe0, 0x36, 0x65, 0x3c, + 0x34, 0xe1, 0x35, 0x84, 0xc9, 0x4d, 0x64, 0xc1, 0xf4, 0x3a, 0xd4, 0xce, 0xc7, 0x59, 0x09, 0xd1, + 0x76, 0x4f, 0xbb, 0x11, 0x8f, 0xb9, 0xef, 0x44, 0x74, 0x31, 0x0c, 0xdc, 0x07, 0x79, 0xd7, 0xb8, + 0x6d, 0x43, 0xdc, 0x8f, 0x89, 0x9e, 0x1e, 0xbf, 0x1a, 0x8f, 0x7f, 0x22, 0x1a, 0x9f, 0xe1, 0x4d, + 0x14, 0xc1, 0x62, 0x9a, 0x2d, 0x64, 0xf3, 0x8b, 0xd7, 0x93, 0xda, 0x23, 0x68, 0xdf, 0xb1, 0x0d, + 0x02, 0xe9, 0xc6, 0xeb, 0x34, 0x97, 0x09, 0x47, 0x73, 0x3d, 0xf2, 0x02, 0x7b, 0xbd, 0xc8, 0x3d, + 0x92, 0x99, 0xea, 0x09, 0x29, 0x36, 0x7f, 0x49, 0x71, 0xbf, 0xf4, 0x3b, 0xeb, 0xad, 0xd4, 0xde, + 0x88, 0xa7, 0x18, 0x69, 0x55, 0xa9, 0x0c, 0xfd, 0x56, 0x95, 0x6a, 0x0f, 0x53, 0xfd, 0x99, 0x03, + 0xc7, 0x68, 0xa0, 0xd7, 0xd5, 0x0c, 0x4b, 0x9f, 0x9a, 0xe9, 0xbb, 0x20, 0x3b, 0x0c, 0xc0, 0xd1, + 0x44, 0x17, 0x13, 0x89, 0xc6, 0xbc, 0x76, 0x0e, 0x0d, 0xa3, 0x0b, 0xb5, 0xcb, 0xf1, 0x34, 0x4f, + 0x31, 0xd3, 0x8c, 0xf9, 0x11, 0x4f, 0x83, 0x93, 0x13, 0xcc, 0xa9, 0xf5, 0xa4, 0xca, 0x3e, 0x43, + 0x3d, 0xe9, 0xf7, 0x7c, 0x72, 0x3d, 0xe3, 0x7e, 0x3b, 0x59, 0x3b, 0xb6, 0x32, 0x6b, 0x3d, 0xe3, + 0x9e, 0xe2, 0xf5, 0x4c, 0x44, 0x0a, 0x52, 0xfd, 0x18, 0x1c, 0x69, 0x61, 0x7d, 0x03, 0x92, 0xb6, + 0xdf, 0xb9, 0xfd, 0x7e, 0xee, 0xce, 0xce, 0x86, 0x6e, 0x51, 0xb3, 0xb3, 0xfb, 0x14, 0xb9, 0x8d, + 0xe6, 0xa3, 0xb7, 0x51, 0x4d, 0xf2, 0x46, 0x60, 0x17, 0xe8, 0x70, 0x2d, 0xd2, 0x5c, 0x93, 0x31, + 0xc4, 0x12, 0x38, 0xce, 0x34, 0x04, 0xec, 0xca, 0xb7, 0x41, 0x2e, 0x48, 0x41, 0xed, 0xee, 0x40, + 0x8f, 0xfb, 0xe6, 0xdd, 0x81, 0x73, 0x29, 0xe6, 0x3a, 0xcd, 0x2b, 0xed, 0x4e, 0x43, 0xd9, 0x7c, + 0xff, 0x7a, 0x53, 0x69, 0x34, 0xd7, 0x9a, 0x57, 0x57, 0x36, 0x57, 0xdb, 0xeb, 0xd9, 0x39, 0xbe, + 0x00, 0x8e, 0xd0, 0xb6, 0xad, 0xf5, 0x7a, 0x7b, 0xbd, 0xb1, 0xba, 0x7e, 0x35, 0xcb, 0xc5, 0xb7, + 0x75, 0x9a, 0x8d, 0x66, 0xeb, 0xba, 0xbb, 0x6d, 0x5e, 0xd8, 0x7d, 0xef, 0xdb, 0xe2, 0x5c, 0xf5, + 0xef, 0x0c, 0xd8, 0xd5, 0xc2, 0x3a, 0x7f, 0x03, 0x64, 0xe8, 0x7f, 0x25, 0x4a, 0x89, 0xe2, 0x45, + 0x47, 0x78, 0xe1, 0xcc, 0x14, 0x40, 0x38, 0xae, 0xde, 0x00, 0x19, 0x7a, 0xee, 0x66, 0x3a, 0xa6, + 0x00, 0x6c, 0xc7, 0xac, 0x39, 0xd8, 0x00, 0x0b, 0xc9, 0x99, 0xf4, 0x34, 0x6b, 0x77, 0x02, 0x26, + 0x2c, 0xcf, 0x04, 0x0b, 0x43, 0x21, 0xf0, 0x2a, 0x6b, 0x84, 0x3c, 0x33, 0xc1, 0x0b, 0x0d, 0x14, + 0xe4, 0x19, 0x81, 0x61, 0xc0, 0xcf, 0x38, 0x50, 0x48, 0x1f, 0xf9, 0x96, 0x27, 0xba, 0x8b, 0xc3, + 0x85, 0xcb, 0xcf, 0x05, 0x0f, 0x39, 0x8c, 0x41, 0x2e, 0x65, 0x42, 0x2b, 0xb3, 0x1c, 0xb2, 0xb1, + 0x42, 0x75, 0x76, 0x6c, 0x18, 0xf9, 0x2b, 0x0e, 0x94, 0xa6, 0x4d, 0x3f, 0x17, 0x59, 0x7e, 0xa7, + 0x6c, 0x12, 0xde, 0x7e, 0x81, 0x4d, 0x21, 0xab, 0x0f, 0xc1, 0xc1, 0xd8, 0xcd, 0x2f, 0xb2, 0x8f, + 0x2a, 0x8d, 0x11, 0xca, 0xd3, 0x31, 0x61, 0x84, 0x21, 0x38, 0xc2, 0xbe, 0xe2, 0xcf, 0xb1, 0x9d, + 0x30, 0xa0, 0x42, 0x65, 0x66, 0x68, 0xe4, 0xb0, 0xa5, 0xdf, 0xe5, 0xcc, 0xc3, 0x96, 0x0a, 0x67, + 0x1f, 0xb6, 0xa9, 0xf7, 0x2c, 0xff, 0x09, 0xc8, 0xa7, 0xde, 0xb1, 0x17, 0x26, 0xba, 0x8c, 0xa1, + 0x85, 0x4b, 0xcf, 0x83, 0x66, 0x6b, 0x90, 0xb8, 0xff, 0x26, 0x6b, 0x10, 0x87, 0x4f, 0xd1, 0x20, + 0xed, 0x6e, 0xe2, 0x77, 0x00, 0xcf, 0xb8, 0x98, 0x96, 0x58, 0xce, 0x92, 0x38, 0x41, 0x9a, 0x0d, + 0x17, 0x44, 0xab, 0xaf, 0x3d, 0x78, 0x5c, 0xe4, 0x1e, 0x3e, 0x2e, 0x72, 0x7f, 0x3e, 0x2e, 0x72, + 0x5f, 0x3e, 0x29, 0xce, 0x3d, 0x7c, 0x52, 0x9c, 0xfb, 0xed, 0x49, 0x71, 0xee, 0x66, 0x95, 0x1a, + 0xcd, 0x37, 0x5c, 0x9f, 0xcb, 0x6b, 0x6a, 0x17, 0xcb, 0xfe, 0x0f, 0x52, 0xa3, 0xca, 0x5b, 0xf2, + 0x98, 0xfa, 0xf9, 0xcc, 0x19, 0xd5, 0xbb, 0x7b, 0xdc, 0x1f, 0xa5, 0x2e, 0xfe, 0x1b, 0x00, 0x00, + 0xff, 0xff, 0xea, 0x02, 0xf9, 0x93, 0x5e, 0x13, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // User transaction to liquid stake native tokens into stTokens + LiquidStake(ctx context.Context, in *MsgLiquidStake, opts ...grpc.CallOption) (*MsgLiquidStakeResponse, error) + // User transaction to redeem stake stTokens into native tokens + RedeemStake(ctx context.Context, in *MsgRedeemStake, opts ...grpc.CallOption) (*MsgRedeemStakeResponse, error) + // Operator transaction to confirm a delegation was submitted + // on the host chain + ConfirmDelegation(ctx context.Context, in *MsgConfirmDelegation, opts ...grpc.CallOption) (*MsgConfirmDelegationResponse, error) + // Operator transaction to confirm an undelegation was submitted + // on the host chain + ConfirmUndelegation(ctx context.Context, in *MsgConfirmUndelegation, opts ...grpc.CallOption) (*MsgConfirmUndelegationResponse, error) + // Operator transaction to confirm unbonded tokens were transferred back to + // stride + ConfirmUnbondedTokenSweep(ctx context.Context, in *MsgConfirmUnbondedTokenSweep, opts ...grpc.CallOption) (*MsgConfirmUnbondedTokenSweepResponse, error) + // Operator transaction to adjust the delegated balance after a validator was + // slashed + AdjustDelegatedBalance(ctx context.Context, in *MsgAdjustDelegatedBalance, opts ...grpc.CallOption) (*MsgAdjustDelegatedBalanceResponse, error) + // Adjusts the inner redemption rate bounds on the host zone + UpdateInnerRedemptionRateBounds(ctx context.Context, in *MsgUpdateInnerRedemptionRateBounds, opts ...grpc.CallOption) (*MsgUpdateInnerRedemptionRateBoundsResponse, error) + // Unhalts the host zone if redemption rates were exceeded + ResumeHostZone(ctx context.Context, in *MsgResumeHostZone, opts ...grpc.CallOption) (*MsgResumeHostZoneResponse, error) + // Trigger updating the redemption rate + RefreshRedemptionRate(ctx context.Context, in *MsgRefreshRedemptionRate, opts ...grpc.CallOption) (*MsgRefreshRedemptionRateResponse, error) + // Overwrites a delegation record + OverwriteDelegationRecord(ctx context.Context, in *MsgOverwriteDelegationRecord, opts ...grpc.CallOption) (*MsgOverwriteDelegationRecordResponse, error) + // Overwrites a unbonding record + OverwriteUnbondingRecord(ctx context.Context, in *MsgOverwriteUnbondingRecord, opts ...grpc.CallOption) (*MsgOverwriteUnbondingRecordResponse, error) + // Overwrites a redemption record + OverwriteRedemptionRecord(ctx context.Context, in *MsgOverwriteRedemptionRecord, opts ...grpc.CallOption) (*MsgOverwriteRedemptionRecordResponse, error) + // Sets the operator address + SetOperatorAddress(ctx context.Context, in *MsgSetOperatorAddress, opts ...grpc.CallOption) (*MsgSetOperatorAddressResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) LiquidStake(ctx context.Context, in *MsgLiquidStake, opts ...grpc.CallOption) (*MsgLiquidStakeResponse, error) { + out := new(MsgLiquidStakeResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/LiquidStake", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) RedeemStake(ctx context.Context, in *MsgRedeemStake, opts ...grpc.CallOption) (*MsgRedeemStakeResponse, error) { + out := new(MsgRedeemStakeResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/RedeemStake", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) ConfirmDelegation(ctx context.Context, in *MsgConfirmDelegation, opts ...grpc.CallOption) (*MsgConfirmDelegationResponse, error) { + out := new(MsgConfirmDelegationResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/ConfirmDelegation", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) ConfirmUndelegation(ctx context.Context, in *MsgConfirmUndelegation, opts ...grpc.CallOption) (*MsgConfirmUndelegationResponse, error) { + out := new(MsgConfirmUndelegationResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/ConfirmUndelegation", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) ConfirmUnbondedTokenSweep(ctx context.Context, in *MsgConfirmUnbondedTokenSweep, opts ...grpc.CallOption) (*MsgConfirmUnbondedTokenSweepResponse, error) { + out := new(MsgConfirmUnbondedTokenSweepResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/ConfirmUnbondedTokenSweep", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) AdjustDelegatedBalance(ctx context.Context, in *MsgAdjustDelegatedBalance, opts ...grpc.CallOption) (*MsgAdjustDelegatedBalanceResponse, error) { + out := new(MsgAdjustDelegatedBalanceResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/AdjustDelegatedBalance", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateInnerRedemptionRateBounds(ctx context.Context, in *MsgUpdateInnerRedemptionRateBounds, opts ...grpc.CallOption) (*MsgUpdateInnerRedemptionRateBoundsResponse, error) { + out := new(MsgUpdateInnerRedemptionRateBoundsResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/UpdateInnerRedemptionRateBounds", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) ResumeHostZone(ctx context.Context, in *MsgResumeHostZone, opts ...grpc.CallOption) (*MsgResumeHostZoneResponse, error) { + out := new(MsgResumeHostZoneResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/ResumeHostZone", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) RefreshRedemptionRate(ctx context.Context, in *MsgRefreshRedemptionRate, opts ...grpc.CallOption) (*MsgRefreshRedemptionRateResponse, error) { + out := new(MsgRefreshRedemptionRateResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/RefreshRedemptionRate", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) OverwriteDelegationRecord(ctx context.Context, in *MsgOverwriteDelegationRecord, opts ...grpc.CallOption) (*MsgOverwriteDelegationRecordResponse, error) { + out := new(MsgOverwriteDelegationRecordResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/OverwriteDelegationRecord", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) OverwriteUnbondingRecord(ctx context.Context, in *MsgOverwriteUnbondingRecord, opts ...grpc.CallOption) (*MsgOverwriteUnbondingRecordResponse, error) { + out := new(MsgOverwriteUnbondingRecordResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/OverwriteUnbondingRecord", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) OverwriteRedemptionRecord(ctx context.Context, in *MsgOverwriteRedemptionRecord, opts ...grpc.CallOption) (*MsgOverwriteRedemptionRecordResponse, error) { + out := new(MsgOverwriteRedemptionRecordResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/OverwriteRedemptionRecord", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) SetOperatorAddress(ctx context.Context, in *MsgSetOperatorAddress, opts ...grpc.CallOption) (*MsgSetOperatorAddressResponse, error) { + out := new(MsgSetOperatorAddressResponse) + err := c.cc.Invoke(ctx, "/stride.stakedym.Msg/SetOperatorAddress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // User transaction to liquid stake native tokens into stTokens + LiquidStake(context.Context, *MsgLiquidStake) (*MsgLiquidStakeResponse, error) + // User transaction to redeem stake stTokens into native tokens + RedeemStake(context.Context, *MsgRedeemStake) (*MsgRedeemStakeResponse, error) + // Operator transaction to confirm a delegation was submitted + // on the host chain + ConfirmDelegation(context.Context, *MsgConfirmDelegation) (*MsgConfirmDelegationResponse, error) + // Operator transaction to confirm an undelegation was submitted + // on the host chain + ConfirmUndelegation(context.Context, *MsgConfirmUndelegation) (*MsgConfirmUndelegationResponse, error) + // Operator transaction to confirm unbonded tokens were transferred back to + // stride + ConfirmUnbondedTokenSweep(context.Context, *MsgConfirmUnbondedTokenSweep) (*MsgConfirmUnbondedTokenSweepResponse, error) + // Operator transaction to adjust the delegated balance after a validator was + // slashed + AdjustDelegatedBalance(context.Context, *MsgAdjustDelegatedBalance) (*MsgAdjustDelegatedBalanceResponse, error) + // Adjusts the inner redemption rate bounds on the host zone + UpdateInnerRedemptionRateBounds(context.Context, *MsgUpdateInnerRedemptionRateBounds) (*MsgUpdateInnerRedemptionRateBoundsResponse, error) + // Unhalts the host zone if redemption rates were exceeded + ResumeHostZone(context.Context, *MsgResumeHostZone) (*MsgResumeHostZoneResponse, error) + // Trigger updating the redemption rate + RefreshRedemptionRate(context.Context, *MsgRefreshRedemptionRate) (*MsgRefreshRedemptionRateResponse, error) + // Overwrites a delegation record + OverwriteDelegationRecord(context.Context, *MsgOverwriteDelegationRecord) (*MsgOverwriteDelegationRecordResponse, error) + // Overwrites a unbonding record + OverwriteUnbondingRecord(context.Context, *MsgOverwriteUnbondingRecord) (*MsgOverwriteUnbondingRecordResponse, error) + // Overwrites a redemption record + OverwriteRedemptionRecord(context.Context, *MsgOverwriteRedemptionRecord) (*MsgOverwriteRedemptionRecordResponse, error) + // Sets the operator address + SetOperatorAddress(context.Context, *MsgSetOperatorAddress) (*MsgSetOperatorAddressResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) LiquidStake(ctx context.Context, req *MsgLiquidStake) (*MsgLiquidStakeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method LiquidStake not implemented") +} +func (*UnimplementedMsgServer) RedeemStake(ctx context.Context, req *MsgRedeemStake) (*MsgRedeemStakeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RedeemStake not implemented") +} +func (*UnimplementedMsgServer) ConfirmDelegation(ctx context.Context, req *MsgConfirmDelegation) (*MsgConfirmDelegationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ConfirmDelegation not implemented") +} +func (*UnimplementedMsgServer) ConfirmUndelegation(ctx context.Context, req *MsgConfirmUndelegation) (*MsgConfirmUndelegationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ConfirmUndelegation not implemented") +} +func (*UnimplementedMsgServer) ConfirmUnbondedTokenSweep(ctx context.Context, req *MsgConfirmUnbondedTokenSweep) (*MsgConfirmUnbondedTokenSweepResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ConfirmUnbondedTokenSweep not implemented") +} +func (*UnimplementedMsgServer) AdjustDelegatedBalance(ctx context.Context, req *MsgAdjustDelegatedBalance) (*MsgAdjustDelegatedBalanceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AdjustDelegatedBalance not implemented") +} +func (*UnimplementedMsgServer) UpdateInnerRedemptionRateBounds(ctx context.Context, req *MsgUpdateInnerRedemptionRateBounds) (*MsgUpdateInnerRedemptionRateBoundsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateInnerRedemptionRateBounds not implemented") +} +func (*UnimplementedMsgServer) ResumeHostZone(ctx context.Context, req *MsgResumeHostZone) (*MsgResumeHostZoneResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ResumeHostZone not implemented") +} +func (*UnimplementedMsgServer) RefreshRedemptionRate(ctx context.Context, req *MsgRefreshRedemptionRate) (*MsgRefreshRedemptionRateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RefreshRedemptionRate not implemented") +} +func (*UnimplementedMsgServer) OverwriteDelegationRecord(ctx context.Context, req *MsgOverwriteDelegationRecord) (*MsgOverwriteDelegationRecordResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method OverwriteDelegationRecord not implemented") +} +func (*UnimplementedMsgServer) OverwriteUnbondingRecord(ctx context.Context, req *MsgOverwriteUnbondingRecord) (*MsgOverwriteUnbondingRecordResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method OverwriteUnbondingRecord not implemented") +} +func (*UnimplementedMsgServer) OverwriteRedemptionRecord(ctx context.Context, req *MsgOverwriteRedemptionRecord) (*MsgOverwriteRedemptionRecordResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method OverwriteRedemptionRecord not implemented") +} +func (*UnimplementedMsgServer) SetOperatorAddress(ctx context.Context, req *MsgSetOperatorAddress) (*MsgSetOperatorAddressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetOperatorAddress not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_LiquidStake_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgLiquidStake) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).LiquidStake(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/LiquidStake", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).LiquidStake(ctx, req.(*MsgLiquidStake)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_RedeemStake_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRedeemStake) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RedeemStake(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/RedeemStake", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RedeemStake(ctx, req.(*MsgRedeemStake)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_ConfirmDelegation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgConfirmDelegation) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ConfirmDelegation(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/ConfirmDelegation", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ConfirmDelegation(ctx, req.(*MsgConfirmDelegation)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_ConfirmUndelegation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgConfirmUndelegation) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ConfirmUndelegation(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/ConfirmUndelegation", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ConfirmUndelegation(ctx, req.(*MsgConfirmUndelegation)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_ConfirmUnbondedTokenSweep_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgConfirmUnbondedTokenSweep) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ConfirmUnbondedTokenSweep(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/ConfirmUnbondedTokenSweep", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ConfirmUnbondedTokenSweep(ctx, req.(*MsgConfirmUnbondedTokenSweep)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_AdjustDelegatedBalance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgAdjustDelegatedBalance) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).AdjustDelegatedBalance(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/AdjustDelegatedBalance", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).AdjustDelegatedBalance(ctx, req.(*MsgAdjustDelegatedBalance)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateInnerRedemptionRateBounds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateInnerRedemptionRateBounds) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateInnerRedemptionRateBounds(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/UpdateInnerRedemptionRateBounds", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateInnerRedemptionRateBounds(ctx, req.(*MsgUpdateInnerRedemptionRateBounds)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_ResumeHostZone_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgResumeHostZone) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ResumeHostZone(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/ResumeHostZone", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ResumeHostZone(ctx, req.(*MsgResumeHostZone)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_RefreshRedemptionRate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRefreshRedemptionRate) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RefreshRedemptionRate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/RefreshRedemptionRate", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RefreshRedemptionRate(ctx, req.(*MsgRefreshRedemptionRate)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_OverwriteDelegationRecord_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgOverwriteDelegationRecord) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).OverwriteDelegationRecord(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/OverwriteDelegationRecord", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).OverwriteDelegationRecord(ctx, req.(*MsgOverwriteDelegationRecord)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_OverwriteUnbondingRecord_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgOverwriteUnbondingRecord) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).OverwriteUnbondingRecord(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/OverwriteUnbondingRecord", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).OverwriteUnbondingRecord(ctx, req.(*MsgOverwriteUnbondingRecord)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_OverwriteRedemptionRecord_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgOverwriteRedemptionRecord) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).OverwriteRedemptionRecord(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/OverwriteRedemptionRecord", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).OverwriteRedemptionRecord(ctx, req.(*MsgOverwriteRedemptionRecord)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_SetOperatorAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSetOperatorAddress) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).SetOperatorAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakedym.Msg/SetOperatorAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).SetOperatorAddress(ctx, req.(*MsgSetOperatorAddress)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "stride.stakedym.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "LiquidStake", + Handler: _Msg_LiquidStake_Handler, + }, + { + MethodName: "RedeemStake", + Handler: _Msg_RedeemStake_Handler, + }, + { + MethodName: "ConfirmDelegation", + Handler: _Msg_ConfirmDelegation_Handler, + }, + { + MethodName: "ConfirmUndelegation", + Handler: _Msg_ConfirmUndelegation_Handler, + }, + { + MethodName: "ConfirmUnbondedTokenSweep", + Handler: _Msg_ConfirmUnbondedTokenSweep_Handler, + }, + { + MethodName: "AdjustDelegatedBalance", + Handler: _Msg_AdjustDelegatedBalance_Handler, + }, + { + MethodName: "UpdateInnerRedemptionRateBounds", + Handler: _Msg_UpdateInnerRedemptionRateBounds_Handler, + }, + { + MethodName: "ResumeHostZone", + Handler: _Msg_ResumeHostZone_Handler, + }, + { + MethodName: "RefreshRedemptionRate", + Handler: _Msg_RefreshRedemptionRate_Handler, + }, + { + MethodName: "OverwriteDelegationRecord", + Handler: _Msg_OverwriteDelegationRecord_Handler, + }, + { + MethodName: "OverwriteUnbondingRecord", + Handler: _Msg_OverwriteUnbondingRecord_Handler, + }, + { + MethodName: "OverwriteRedemptionRecord", + Handler: _Msg_OverwriteRedemptionRecord_Handler, + }, + { + MethodName: "SetOperatorAddress", + Handler: _Msg_SetOperatorAddress_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "stride/stakedym/tx.proto", +} + +func (m *MsgLiquidStake) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgLiquidStake) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgLiquidStake) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.NativeAmount.Size() + i -= size + if _, err := m.NativeAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Staker) > 0 { + i -= len(m.Staker) + copy(dAtA[i:], m.Staker) + i = encodeVarintTx(dAtA, i, uint64(len(m.Staker))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgLiquidStakeResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgLiquidStakeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgLiquidStakeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.StToken.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgRedeemStake) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRedeemStake) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRedeemStake) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.StTokenAmount.Size() + i -= size + if _, err := m.StTokenAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Redeemer) > 0 { + i -= len(m.Redeemer) + copy(dAtA[i:], m.Redeemer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Redeemer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRedeemStakeResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRedeemStakeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRedeemStakeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.NativeToken.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgConfirmDelegation) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgConfirmDelegation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgConfirmDelegation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TxHash) > 0 { + i -= len(m.TxHash) + copy(dAtA[i:], m.TxHash) + i = encodeVarintTx(dAtA, i, uint64(len(m.TxHash))) + i-- + dAtA[i] = 0x1a + } + if m.RecordId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.RecordId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Operator) > 0 { + i -= len(m.Operator) + copy(dAtA[i:], m.Operator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Operator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgConfirmDelegationResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgConfirmDelegationResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgConfirmDelegationResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgConfirmUndelegation) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgConfirmUndelegation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgConfirmUndelegation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TxHash) > 0 { + i -= len(m.TxHash) + copy(dAtA[i:], m.TxHash) + i = encodeVarintTx(dAtA, i, uint64(len(m.TxHash))) + i-- + dAtA[i] = 0x1a + } + if m.RecordId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.RecordId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Operator) > 0 { + i -= len(m.Operator) + copy(dAtA[i:], m.Operator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Operator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgConfirmUndelegationResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgConfirmUndelegationResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgConfirmUndelegationResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgConfirmUnbondedTokenSweep) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgConfirmUnbondedTokenSweep) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgConfirmUnbondedTokenSweep) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TxHash) > 0 { + i -= len(m.TxHash) + copy(dAtA[i:], m.TxHash) + i = encodeVarintTx(dAtA, i, uint64(len(m.TxHash))) + i-- + dAtA[i] = 0x1a + } + if m.RecordId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.RecordId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Operator) > 0 { + i -= len(m.Operator) + copy(dAtA[i:], m.Operator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Operator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgConfirmUnbondedTokenSweepResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgConfirmUnbondedTokenSweepResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgConfirmUnbondedTokenSweepResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgAdjustDelegatedBalance) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgAdjustDelegatedBalance) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAdjustDelegatedBalance) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0x1a + } + { + size := m.DelegationOffset.Size() + i -= size + if _, err := m.DelegationOffset.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Operator) > 0 { + i -= len(m.Operator) + copy(dAtA[i:], m.Operator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Operator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgAdjustDelegatedBalanceResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgAdjustDelegatedBalanceResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAdjustDelegatedBalanceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgUpdateInnerRedemptionRateBounds) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateInnerRedemptionRateBounds) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateInnerRedemptionRateBounds) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.MaxInnerRedemptionRate.Size() + i -= size + if _, err := m.MaxInnerRedemptionRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size := m.MinInnerRedemptionRate.Size() + i -= size + if _, err := m.MinInnerRedemptionRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgResumeHostZone) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgResumeHostZone) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgResumeHostZone) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgResumeHostZoneResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgResumeHostZoneResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgResumeHostZoneResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgRefreshRedemptionRate) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRefreshRedemptionRate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRefreshRedemptionRate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRefreshRedemptionRateResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRefreshRedemptionRateResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRefreshRedemptionRateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgOverwriteDelegationRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgOverwriteDelegationRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOverwriteDelegationRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.DelegationRecord != nil { + { + size, err := m.DelegationRecord.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgOverwriteDelegationRecordResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgOverwriteDelegationRecordResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOverwriteDelegationRecordResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgOverwriteUnbondingRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgOverwriteUnbondingRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOverwriteUnbondingRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.UnbondingRecord != nil { + { + size, err := m.UnbondingRecord.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgOverwriteUnbondingRecordResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgOverwriteUnbondingRecordResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOverwriteUnbondingRecordResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgOverwriteRedemptionRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgOverwriteRedemptionRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOverwriteRedemptionRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.RedemptionRecord != nil { + { + size, err := m.RedemptionRecord.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgOverwriteRedemptionRecordResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgOverwriteRedemptionRecordResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOverwriteRedemptionRecordResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgSetOperatorAddress) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSetOperatorAddress) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSetOperatorAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Operator) > 0 { + i -= len(m.Operator) + copy(dAtA[i:], m.Operator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Operator))) + i-- + dAtA[i] = 0x12 + } + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSetOperatorAddressResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSetOperatorAddressResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSetOperatorAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgLiquidStake) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Staker) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.NativeAmount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgLiquidStakeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.StToken.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgRedeemStake) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Redeemer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.StTokenAmount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgRedeemStakeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.NativeToken.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgConfirmDelegation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Operator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.RecordId != 0 { + n += 1 + sovTx(uint64(m.RecordId)) + } + l = len(m.TxHash) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgConfirmDelegationResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgConfirmUndelegation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Operator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.RecordId != 0 { + n += 1 + sovTx(uint64(m.RecordId)) + } + l = len(m.TxHash) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgConfirmUndelegationResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgConfirmUnbondedTokenSweep) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Operator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.RecordId != 0 { + n += 1 + sovTx(uint64(m.RecordId)) + } + l = len(m.TxHash) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgConfirmUnbondedTokenSweepResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgAdjustDelegatedBalance) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Operator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.DelegationOffset.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgAdjustDelegatedBalanceResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateInnerRedemptionRateBounds) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.MinInnerRedemptionRate.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.MaxInnerRedemptionRate.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgResumeHostZone) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgResumeHostZoneResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgRefreshRedemptionRate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRefreshRedemptionRateResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgOverwriteDelegationRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.DelegationRecord != nil { + l = m.DelegationRecord.Size() + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgOverwriteDelegationRecordResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgOverwriteUnbondingRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.UnbondingRecord != nil { + l = m.UnbondingRecord.Size() + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgOverwriteUnbondingRecordResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgOverwriteRedemptionRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.RedemptionRecord != nil { + l = m.RedemptionRecord.Size() + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgOverwriteRedemptionRecordResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgSetOperatorAddress) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Operator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgSetOperatorAddressResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgLiquidStake) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgLiquidStake: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgLiquidStake: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Staker", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Staker = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NativeAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.NativeAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgLiquidStakeResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgLiquidStakeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgLiquidStakeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StToken", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StToken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRedeemStake) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRedeemStake: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRedeemStake: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Redeemer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Redeemer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StTokenAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StTokenAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRedeemStakeResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRedeemStakeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRedeemStakeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NativeToken", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.NativeToken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgConfirmDelegation) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConfirmDelegation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConfirmDelegation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Operator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Operator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RecordId", wireType) + } + m.RecordId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RecordId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgConfirmDelegationResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConfirmDelegationResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConfirmDelegationResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgConfirmUndelegation) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConfirmUndelegation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConfirmUndelegation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Operator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Operator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RecordId", wireType) + } + m.RecordId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RecordId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgConfirmUndelegationResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConfirmUndelegationResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConfirmUndelegationResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgConfirmUnbondedTokenSweep) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConfirmUnbondedTokenSweep: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConfirmUnbondedTokenSweep: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Operator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Operator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RecordId", wireType) + } + m.RecordId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RecordId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgConfirmUnbondedTokenSweepResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConfirmUnbondedTokenSweepResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConfirmUnbondedTokenSweepResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgAdjustDelegatedBalance) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgAdjustDelegatedBalance: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAdjustDelegatedBalance: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Operator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Operator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegationOffset", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.DelegationOffset.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgAdjustDelegatedBalanceResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgAdjustDelegatedBalanceResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAdjustDelegatedBalanceResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateInnerRedemptionRateBounds) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateInnerRedemptionRateBounds: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateInnerRedemptionRateBounds: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinInnerRedemptionRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinInnerRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxInnerRedemptionRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxInnerRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateInnerRedemptionRateBoundsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateInnerRedemptionRateBoundsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgResumeHostZone) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgResumeHostZone: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgResumeHostZone: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgResumeHostZoneResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgResumeHostZoneResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgResumeHostZoneResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRefreshRedemptionRate) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRefreshRedemptionRate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRefreshRedemptionRate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRefreshRedemptionRateResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRefreshRedemptionRateResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRefreshRedemptionRateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgOverwriteDelegationRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgOverwriteDelegationRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOverwriteDelegationRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegationRecord", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.DelegationRecord == nil { + m.DelegationRecord = &DelegationRecord{} + } + if err := m.DelegationRecord.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgOverwriteDelegationRecordResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgOverwriteDelegationRecordResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOverwriteDelegationRecordResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgOverwriteUnbondingRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgOverwriteUnbondingRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOverwriteUnbondingRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingRecord", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.UnbondingRecord == nil { + m.UnbondingRecord = &UnbondingRecord{} + } + if err := m.UnbondingRecord.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgOverwriteUnbondingRecordResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgOverwriteUnbondingRecordResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOverwriteUnbondingRecordResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgOverwriteRedemptionRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgOverwriteRedemptionRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOverwriteRedemptionRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RedemptionRecord", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RedemptionRecord == nil { + m.RedemptionRecord = &RedemptionRecord{} + } + if err := m.RedemptionRecord.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgOverwriteRedemptionRecordResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgOverwriteRedemptionRecordResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOverwriteRedemptionRecordResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSetOperatorAddress) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSetOperatorAddress: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSetOperatorAddress: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Operator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Operator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSetOperatorAddressResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSetOperatorAddressResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSetOperatorAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +)