From 7eba66ed8fc3552dfd4f32de81b8ef36bad4b591 Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Fri, 20 Feb 2026 09:49:32 +0300 Subject: [PATCH 01/13] add distribution_id key to ScheduledDistribution proto --- docs/api.md | 2 + docs/static/openapi.json | 7 ++- proto/tx/pse/v1/distribution.proto | 7 +++ x/pse/types/distribution.pb.go | 98 +++++++++++++++++++++--------- 4 files changed, 84 insertions(+), 30 deletions(-) diff --git a/docs/api.md b/docs/api.md index 24cd10fb..aa09ef16 100644 --- a/docs/api.md +++ b/docs/api.md @@ -5818,6 +5818,7 @@ During distribution, the allocated amount is split equally among all recipients. ``` ScheduledDistribution defines a single allocation event at a specific timestamp. Multiple clearing accounts can allocate tokens at the same time. +Each distribution is identified by a unique, sequential distribution_id. ``` @@ -5826,6 +5827,7 @@ Multiple clearing accounts can allocate tokens at the same time. | ----- | ---- | ----- | ----------- | | `timestamp` | [uint64](#uint64) | | `timestamp is when this allocation should occur (Unix timestamp in seconds).` | | `allocations` | [ClearingAccountAllocation](#tx.pse.v1.ClearingAccountAllocation) | repeated | `allocations is the list of amounts to allocate from each clearing account at this time.` | +| `distribution_id` | [uint64](#uint64) | | `distribution_id is the unique, sequential identifier for this distribution. Used as the storage key in the AllocationSchedule map.` | diff --git a/docs/static/openapi.json b/docs/static/openapi.json index 31af7372..d47da82b 100644 --- a/docs/static/openapi.json +++ b/docs/static/openapi.json @@ -16874,9 +16874,14 @@ "$ref": "#/definitions/tx.pse.v1.ClearingAccountAllocation" }, "description": "allocations is the list of amounts to allocate from each clearing account at this time." + }, + "distribution_id": { + "type": "string", + "format": "uint64", + "description": "distribution_id is the unique, sequential identifier for this distribution.\nUsed as the storage key in the AllocationSchedule map." } }, - "description": "ScheduledDistribution defines a single allocation event at a specific timestamp.\nMultiple clearing accounts can allocate tokens at the same time." + "description": "ScheduledDistribution defines a single allocation event at a specific timestamp.\nMultiple clearing accounts can allocate tokens at the same time.\nEach distribution is identified by a unique, sequential distribution_id." } } } diff --git a/proto/tx/pse/v1/distribution.proto b/proto/tx/pse/v1/distribution.proto index f2769a4a..17add0ee 100644 --- a/proto/tx/pse/v1/distribution.proto +++ b/proto/tx/pse/v1/distribution.proto @@ -43,6 +43,7 @@ message ClearingAccountAllocation { // ScheduledDistribution defines a single allocation event at a specific timestamp. // Multiple clearing accounts can allocate tokens at the same time. +// Each distribution is identified by a unique, sequential distribution_id. message ScheduledDistribution { // timestamp is when this allocation should occur (Unix timestamp in seconds). uint64 timestamp = 1 [ @@ -54,5 +55,11 @@ message ScheduledDistribution { (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"allocations\"" ]; + + // distribution_id is the unique, sequential identifier for this distribution. + // Used as the storage key in the AllocationSchedule map. + uint64 distribution_id = 3 [ + (gogoproto.moretags) = "yaml:\"distribution_id\"" + ]; } diff --git a/x/pse/types/distribution.pb.go b/x/pse/types/distribution.pb.go index 53de4c0f..b3732429 100644 --- a/x/pse/types/distribution.pb.go +++ b/x/pse/types/distribution.pb.go @@ -135,11 +135,15 @@ func (m *ClearingAccountAllocation) GetClearingAccount() string { // ScheduledDistribution defines a single allocation event at a specific timestamp. // Multiple clearing accounts can allocate tokens at the same time. +// Each distribution is identified by a unique, sequential distribution_id. type ScheduledDistribution struct { // timestamp is when this allocation should occur (Unix timestamp in seconds). Timestamp uint64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty" yaml:"timestamp"` // allocations is the list of amounts to allocate from each clearing account at this time. Allocations []ClearingAccountAllocation `protobuf:"bytes,2,rep,name=allocations,proto3" json:"allocations" yaml:"allocations"` + // distribution_id is the unique, sequential identifier for this distribution. + // Used as the storage key in the AllocationSchedule map. + DistributionId uint64 `protobuf:"varint,3,opt,name=distribution_id,json=distributionId,proto3" json:"distribution_id,omitempty" yaml:"distribution_id"` } func (m *ScheduledDistribution) Reset() { *m = ScheduledDistribution{} } @@ -189,6 +193,13 @@ func (m *ScheduledDistribution) GetAllocations() []ClearingAccountAllocation { return nil } +func (m *ScheduledDistribution) GetDistributionId() uint64 { + if m != nil { + return m.DistributionId + } + return 0 +} + func init() { proto.RegisterType((*ClearingAccountMapping)(nil), "tx.pse.v1.ClearingAccountMapping") proto.RegisterType((*ClearingAccountAllocation)(nil), "tx.pse.v1.ClearingAccountAllocation") @@ -198,35 +209,37 @@ func init() { func init() { proto.RegisterFile("tx/pse/v1/distribution.proto", fileDescriptor_a549fe743b42ab69) } var fileDescriptor_a549fe743b42ab69 = []byte{ - // 442 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x92, 0x41, 0x6b, 0xd4, 0x40, - 0x14, 0xc7, 0x77, 0xaa, 0x14, 0x76, 0x8a, 0x58, 0xe2, 0x56, 0xdb, 0x55, 0x92, 0x12, 0x3c, 0xf4, - 0xb2, 0x33, 0xb4, 0x82, 0x82, 0x78, 0xd9, 0x28, 0x4a, 0x0f, 0x5e, 0x52, 0x4f, 0x5e, 0x96, 0xd9, - 0xc9, 0x90, 0x1d, 0x9a, 0xcc, 0x0c, 0x99, 0xb7, 0xcb, 0xd6, 0x4f, 0xe1, 0x37, 0xf1, 0xe2, 0xc5, - 0x6f, 0x50, 0x6f, 0xc5, 0x93, 0x78, 0x08, 0xb2, 0xfb, 0x0d, 0xf2, 0x09, 0x24, 0x99, 0x90, 0xd6, - 0x45, 0x6f, 0xbd, 0x25, 0xef, 0xff, 0x7f, 0x3f, 0xde, 0xff, 0xcd, 0xc3, 0x4f, 0x60, 0x49, 0x8d, - 0x15, 0x74, 0x71, 0x4c, 0x13, 0x69, 0xa1, 0x90, 0xd3, 0x39, 0x48, 0xad, 0x88, 0x29, 0x34, 0x68, - 0xaf, 0x0f, 0x4b, 0x62, 0xac, 0x20, 0x8b, 0xe3, 0xe1, 0x20, 0xd5, 0xa9, 0x6e, 0xaa, 0xb4, 0xfe, - 0x72, 0x86, 0xe1, 0x01, 0xd7, 0x36, 0xd7, 0x76, 0xe2, 0x04, 0xf7, 0xe3, 0xa4, 0xf0, 0x3b, 0xc2, - 0x0f, 0x5f, 0x67, 0x82, 0x15, 0x52, 0xa5, 0x63, 0xce, 0xf5, 0x5c, 0xc1, 0x7b, 0x66, 0x8c, 0x54, - 0xa9, 0xf7, 0x16, 0xef, 0xf2, 0x56, 0x99, 0x30, 0x27, 0xed, 0xa3, 0x43, 0x74, 0xd4, 0x8f, 0x1e, - 0x57, 0x65, 0xf0, 0xe8, 0x82, 0xe5, 0xd9, 0xcb, 0x70, 0xd3, 0x11, 0xc6, 0xf7, 0xf9, 0xdf, 0x38, - 0x2f, 0xc5, 0x0f, 0x0a, 0xc1, 0xa5, 0x91, 0x42, 0xc1, 0x84, 0x25, 0x49, 0x21, 0xac, 0x15, 0x76, - 0x7f, 0xeb, 0xf0, 0xce, 0x51, 0x3f, 0x7a, 0x5e, 0x95, 0xc1, 0xd0, 0xa1, 0xfe, 0x61, 0x0a, 0x7f, - 0x7c, 0x1d, 0x0d, 0xda, 0x79, 0xc7, 0xae, 0x78, 0x06, 0x35, 0x3b, 0xf6, 0x3a, 0xf7, 0xb8, 0x33, - 0x7f, 0x43, 0xf8, 0x60, 0x23, 0xcb, 0x38, 0xcb, 0x34, 0x67, 0xf5, 0xae, 0x6e, 0x2d, 0xce, 0x07, - 0xbc, 0xcd, 0xf2, 0xa6, 0x7b, 0xab, 0xe9, 0x7e, 0x75, 0x59, 0x06, 0xbd, 0x5f, 0x65, 0xb0, 0xe7, - 0xe6, 0xb4, 0xc9, 0x39, 0x91, 0x9a, 0xe6, 0x0c, 0x66, 0xe4, 0x54, 0x41, 0x55, 0x06, 0xf7, 0x1c, - 0xda, 0x35, 0xd5, 0x89, 0x70, 0x9b, 0xe8, 0x54, 0x41, 0xdc, 0xb2, 0xc2, 0x2f, 0x08, 0xef, 0x9d, - 0xf1, 0x99, 0x48, 0xe6, 0x99, 0x48, 0xde, 0xdc, 0x78, 0x63, 0xef, 0x04, 0xf7, 0x41, 0xe6, 0xc2, - 0x02, 0xcb, 0x4d, 0x33, 0xf0, 0xdd, 0x68, 0x50, 0x95, 0xc1, 0xae, 0xa3, 0x76, 0x52, 0x18, 0x5f, - 0xdb, 0xbc, 0x29, 0xde, 0x61, 0x5d, 0x72, 0xb7, 0xea, 0x9d, 0x93, 0xa7, 0xa4, 0xbb, 0x13, 0xf2, - 0xdf, 0x35, 0x45, 0xc3, 0x3a, 0x4e, 0x55, 0x06, 0x5e, 0x3b, 0xf5, 0x35, 0x26, 0x8c, 0x6f, 0x42, - 0xa3, 0x77, 0x97, 0x2b, 0x1f, 0x5d, 0xad, 0x7c, 0xf4, 0x7b, 0xe5, 0xa3, 0xcf, 0x6b, 0xbf, 0x77, - 0xb5, 0xf6, 0x7b, 0x3f, 0xd7, 0x7e, 0xef, 0xe3, 0x28, 0x95, 0x30, 0x9b, 0x4f, 0x09, 0xd7, 0x39, - 0x05, 0x7d, 0x2e, 0x94, 0xfc, 0x24, 0x46, 0x4b, 0x0a, 0xcb, 0x11, 0x9f, 0x31, 0xa9, 0xe8, 0xe2, - 0x05, 0x75, 0xe7, 0x0c, 0x17, 0x46, 0xd8, 0xe9, 0x76, 0x73, 0x89, 0xcf, 0xfe, 0x04, 0x00, 0x00, - 0xff, 0xff, 0x58, 0x32, 0x8e, 0xed, 0xe5, 0x02, 0x00, 0x00, + // 466 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0xbf, 0x6e, 0xd3, 0x40, + 0x18, 0x8f, 0x5b, 0x54, 0x29, 0x57, 0x41, 0x2b, 0x93, 0x96, 0xd4, 0x20, 0xbb, 0xb2, 0x18, 0xba, + 0xc4, 0xa7, 0x16, 0x09, 0x24, 0xc4, 0x12, 0x17, 0x81, 0x32, 0xb0, 0xb8, 0x4c, 0x2c, 0xd1, 0xe5, + 0x7c, 0x72, 0x4e, 0xb5, 0xef, 0x2c, 0xdf, 0x97, 0x28, 0xe5, 0x29, 0x78, 0x18, 0x16, 0xde, 0xa0, + 0x6c, 0x15, 0x13, 0x62, 0x38, 0xa1, 0xe4, 0x0d, 0x2c, 0x1e, 0x00, 0xd9, 0x67, 0x39, 0x21, 0x82, + 0x8d, 0xcd, 0xfe, 0x7e, 0x7f, 0xf4, 0xfb, 0x7d, 0xfe, 0x8c, 0x9e, 0xc0, 0x02, 0xe7, 0x8a, 0xe1, + 0xf9, 0x39, 0x8e, 0xb9, 0x82, 0x82, 0x4f, 0x66, 0xc0, 0xa5, 0x08, 0xf2, 0x42, 0x82, 0xb4, 0xbb, + 0xb0, 0x08, 0x72, 0xc5, 0x82, 0xf9, 0xb9, 0xd3, 0x4b, 0x64, 0x22, 0xeb, 0x29, 0xae, 0x9e, 0x0c, + 0xc1, 0x39, 0xa1, 0x52, 0x65, 0x52, 0x8d, 0x0d, 0x60, 0x5e, 0x0c, 0xe4, 0x7f, 0xb5, 0xd0, 0xf1, + 0x65, 0xca, 0x48, 0xc1, 0x45, 0x32, 0xa4, 0x54, 0xce, 0x04, 0xbc, 0x23, 0x79, 0xce, 0x45, 0x62, + 0xbf, 0x41, 0x87, 0xb4, 0x41, 0xc6, 0xc4, 0x40, 0x7d, 0xeb, 0xd4, 0x3a, 0xeb, 0x86, 0x8f, 0x4b, + 0xed, 0x3d, 0xba, 0x21, 0x59, 0xfa, 0xd2, 0xdf, 0x66, 0xf8, 0xd1, 0x01, 0xfd, 0xd3, 0xce, 0x4e, + 0xd0, 0xc3, 0x82, 0x51, 0x9e, 0x73, 0x26, 0x60, 0x4c, 0xe2, 0xb8, 0x60, 0x4a, 0x31, 0xd5, 0xdf, + 0x39, 0xdd, 0x3d, 0xeb, 0x86, 0xcf, 0x4b, 0xed, 0x39, 0xc6, 0xea, 0x2f, 0x24, 0xff, 0xdb, 0xe7, + 0x41, 0xaf, 0xc9, 0x3b, 0x34, 0xc3, 0x2b, 0xa8, 0xbc, 0x23, 0xbb, 0x65, 0x0f, 0x5b, 0xf2, 0x17, + 0x0b, 0x9d, 0x6c, 0x75, 0x19, 0xa6, 0xa9, 0xa4, 0xa4, 0xda, 0xd5, 0x7f, 0xab, 0xf3, 0x1e, 0xed, + 0x91, 0xac, 0x56, 0xef, 0xd4, 0xea, 0x57, 0xb7, 0xda, 0xeb, 0xfc, 0xd0, 0xde, 0x91, 0xc9, 0xa9, + 0xe2, 0xeb, 0x80, 0x4b, 0x9c, 0x11, 0x98, 0x06, 0x23, 0x01, 0xa5, 0xf6, 0xee, 0x1b, 0x6b, 0x23, + 0xaa, 0x1a, 0xa1, 0xa6, 0xd1, 0x48, 0x40, 0xd4, 0x78, 0xf9, 0xbf, 0x2c, 0x74, 0x74, 0x45, 0xa7, + 0x2c, 0x9e, 0xa5, 0x2c, 0x7e, 0xbd, 0xf1, 0x8d, 0xed, 0x0b, 0xd4, 0x05, 0x9e, 0x31, 0x05, 0x24, + 0xcb, 0xeb, 0xc0, 0xf7, 0xc2, 0x5e, 0xa9, 0xbd, 0x43, 0xe3, 0xda, 0x42, 0x7e, 0xb4, 0xa6, 0xd9, + 0x13, 0xb4, 0x4f, 0xda, 0xe6, 0x66, 0xd5, 0xfb, 0x17, 0x4f, 0x83, 0xf6, 0x4e, 0x82, 0x7f, 0xae, + 0x29, 0x74, 0xaa, 0x3a, 0xa5, 0xf6, 0xec, 0x26, 0xf5, 0xda, 0xc6, 0x8f, 0x36, 0x4d, 0xed, 0x4b, + 0x74, 0xb0, 0x79, 0x8b, 0x63, 0x1e, 0xf7, 0x77, 0xeb, 0x74, 0x4e, 0xa9, 0xbd, 0x63, 0xa3, 0xde, + 0x22, 0xf8, 0xd1, 0x83, 0xcd, 0xc9, 0x28, 0x0e, 0xdf, 0xde, 0x2e, 0x5d, 0xeb, 0x6e, 0xe9, 0x5a, + 0x3f, 0x97, 0xae, 0xf5, 0x69, 0xe5, 0x76, 0xee, 0x56, 0x6e, 0xe7, 0xfb, 0xca, 0xed, 0x7c, 0x18, + 0x24, 0x1c, 0xa6, 0xb3, 0x49, 0x40, 0x65, 0x86, 0x41, 0x5e, 0x33, 0xc1, 0x3f, 0xb2, 0xc1, 0x02, + 0xc3, 0x62, 0x40, 0xa7, 0x84, 0x0b, 0x3c, 0x7f, 0x81, 0xcd, 0x3f, 0x01, 0x37, 0x39, 0x53, 0x93, + 0xbd, 0xfa, 0x9c, 0x9f, 0xfd, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x8c, 0x50, 0x13, 0x8c, 0x2a, 0x03, + 0x00, 0x00, } func (m *ClearingAccountMapping) Marshal() (dAtA []byte, err error) { @@ -328,6 +341,11 @@ func (m *ScheduledDistribution) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.DistributionId != 0 { + i = encodeVarintDistribution(dAtA, i, uint64(m.DistributionId)) + i-- + dAtA[i] = 0x18 + } if len(m.Allocations) > 0 { for iNdEx := len(m.Allocations) - 1; iNdEx >= 0; iNdEx-- { { @@ -410,6 +428,9 @@ func (m *ScheduledDistribution) Size() (n int) { n += 1 + l + sovDistribution(uint64(l)) } } + if m.DistributionId != 0 { + n += 1 + sovDistribution(uint64(m.DistributionId)) + } return n } @@ -731,6 +752,25 @@ func (m *ScheduledDistribution) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DistributionId", wireType) + } + m.DistributionId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDistribution + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DistributionId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipDistribution(dAtA[iNdEx:]) From 36e946b9f7a92cbb90ac3eb1d55f291710ee53b6 Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Fri, 20 Feb 2026 10:34:58 +0300 Subject: [PATCH 02/13] add min_distribution_gap_seconds param to PSE --- docs/api.md | 1 + docs/static/openapi.json | 5 +++ proto/tx/pse/v1/params.proto | 5 +++ x/pse/types/params.pb.go | 83 ++++++++++++++++++++++++++---------- 4 files changed, 72 insertions(+), 22 deletions(-) diff --git a/docs/api.md b/docs/api.md index aa09ef16..41effa84 100644 --- a/docs/api.md +++ b/docs/api.md @@ -5998,6 +5998,7 @@ Params store gov manageable parameters. | ----- | ---- | ----- | ----------- | | `excluded_addresses` | [string](#string) | repeated | `excluded_addresses is a list of addresses excluded from PSE distribution. This list includes account addresses that should not receive PSE rewards. Can be modified via governance proposals.` | | `clearing_account_mappings` | [ClearingAccountMapping](#tx.pse.v1.ClearingAccountMapping) | repeated | `clearing_account_mappings defines the mapping between clearing accounts and their sub accounts (multisig wallets). These mappings can be modified via governance proposals.` | +| `min_distribution_gap_seconds` | [uint64](#uint64) | | `min_distribution_gap_seconds is the minimum required gap in seconds between consecutive distributions.` | diff --git a/docs/static/openapi.json b/docs/static/openapi.json index d47da82b..fa222086 100644 --- a/docs/static/openapi.json +++ b/docs/static/openapi.json @@ -16804,6 +16804,11 @@ "$ref": "#/definitions/tx.pse.v1.ClearingAccountMapping" }, "description": "clearing_account_mappings defines the mapping between clearing accounts and their sub accounts (multisig wallets).\nThese mappings can be modified via governance proposals." + }, + "min_distribution_gap_seconds": { + "type": "string", + "format": "uint64", + "description": "min_distribution_gap_seconds is the minimum required gap in seconds between consecutive distributions." } }, "description": "Params store gov manageable parameters." diff --git a/proto/tx/pse/v1/params.proto b/proto/tx/pse/v1/params.proto index 471ee613..d1e22369 100644 --- a/proto/tx/pse/v1/params.proto +++ b/proto/tx/pse/v1/params.proto @@ -23,4 +23,9 @@ message Params { (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"clearing_account_mappings\"" ]; + + // min_distribution_gap_seconds is the minimum required gap in seconds between consecutive distributions. + uint64 min_distribution_gap_seconds = 3 [ + (gogoproto.moretags) = "yaml:\"min_distribution_gap_seconds\"" + ]; } diff --git a/x/pse/types/params.pb.go b/x/pse/types/params.pb.go index 8067742b..56ad25db 100644 --- a/x/pse/types/params.pb.go +++ b/x/pse/types/params.pb.go @@ -33,6 +33,8 @@ type Params struct { // clearing_account_mappings defines the mapping between clearing accounts and their sub accounts (multisig wallets). // These mappings can be modified via governance proposals. ClearingAccountMappings []ClearingAccountMapping `protobuf:"bytes,2,rep,name=clearing_account_mappings,json=clearingAccountMappings,proto3" json:"clearing_account_mappings" yaml:"clearing_account_mappings"` + // min_distribution_gap_seconds is the minimum required gap in seconds between consecutive distributions. + MinDistributionGapSeconds uint64 `protobuf:"varint,3,opt,name=min_distribution_gap_seconds,json=minDistributionGapSeconds,proto3" json:"min_distribution_gap_seconds,omitempty" yaml:"min_distribution_gap_seconds"` } func (m *Params) Reset() { *m = Params{} } @@ -82,6 +84,13 @@ func (m *Params) GetClearingAccountMappings() []ClearingAccountMapping { return nil } +func (m *Params) GetMinDistributionGapSeconds() uint64 { + if m != nil { + return m.MinDistributionGapSeconds + } + return 0 +} + func init() { proto.RegisterType((*Params)(nil), "tx.pse.v1.Params") } @@ -89,28 +98,31 @@ func init() { func init() { proto.RegisterFile("tx/pse/v1/params.proto", fileDescriptor_b70a3fad281b1b5f) } var fileDescriptor_b70a3fad281b1b5f = []byte{ - // 324 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x90, 0x31, 0x4f, 0x32, 0x31, - 0x1c, 0xc6, 0xef, 0x5e, 0x12, 0x12, 0xee, 0x9d, 0xbc, 0x10, 0x05, 0x62, 0x0e, 0xbc, 0x89, 0xe5, - 0xda, 0xa0, 0x31, 0x26, 0x6e, 0xe0, 0xe0, 0x64, 0x62, 0x70, 0x73, 0xb9, 0x94, 0xb6, 0x39, 0x1a, - 0xb9, 0xb6, 0xb9, 0x7f, 0x8f, 0x1c, 0x7e, 0x01, 0x57, 0x3f, 0x8c, 0x1f, 0x82, 0x91, 0x38, 0x39, - 0x11, 0x03, 0xdf, 0x80, 0xc9, 0xd1, 0x40, 0x0f, 0x1d, 0xd4, 0xad, 0x7d, 0x9e, 0x5f, 0x9e, 0x3e, - 0x7d, 0xbc, 0x43, 0x53, 0x60, 0x0d, 0x1c, 0x4f, 0x7b, 0x58, 0x93, 0x8c, 0xa4, 0x80, 0x74, 0xa6, - 0x8c, 0xf2, 0x6b, 0xa6, 0x40, 0x1a, 0x38, 0x9a, 0xf6, 0x5a, 0x4d, 0xaa, 0x20, 0x55, 0x10, 0xef, - 0x0c, 0x6c, 0x2f, 0x96, 0x6a, 0xd5, 0x13, 0x95, 0x28, 0xab, 0x6f, 0x4f, 0xa5, 0x7a, 0xfc, 0x9d, - 0xc9, 0x04, 0x98, 0x4c, 0x8c, 0x72, 0x23, 0x94, 0xb4, 0x6e, 0xf8, 0xe1, 0x7a, 0xd5, 0xdb, 0xdd, - 0x53, 0x3e, 0xf3, 0x7c, 0x5e, 0xd0, 0x49, 0xce, 0x38, 0x8b, 0x09, 0x63, 0x19, 0x07, 0xe0, 0xd0, - 0x70, 0x3b, 0x95, 0x6e, 0x6d, 0x70, 0xbe, 0x59, 0xb6, 0x9b, 0x33, 0x92, 0x4e, 0x2e, 0xc3, 0x9f, - 0x4c, 0xf8, 0xfa, 0x12, 0xd5, 0xcb, 0x26, 0x7d, 0x2b, 0xde, 0x99, 0x4c, 0xc8, 0x64, 0x78, 0xb0, - 0x87, 0xfb, 0x7b, 0xd6, 0x7f, 0x72, 0xbd, 0x26, 0x9d, 0x70, 0xb2, 0xf5, 0x63, 0x42, 0xa9, 0xca, - 0xa5, 0x89, 0x53, 0xa2, 0xb5, 0x90, 0x09, 0x34, 0xfe, 0x75, 0x2a, 0xdd, 0xff, 0xa7, 0x27, 0xe8, - 0xeb, 0xbf, 0xe8, 0xaa, 0x64, 0xfb, 0x16, 0xbd, 0xb1, 0xe4, 0xa0, 0x3b, 0x5f, 0xb6, 0x9d, 0xcd, - 0xb2, 0xdd, 0xb1, 0xa5, 0xfe, 0x4c, 0x0c, 0x87, 0x47, 0xf4, 0xd7, 0x04, 0x18, 0x5c, 0xcf, 0x57, - 0x81, 0xbb, 0x58, 0x05, 0xee, 0xfb, 0x2a, 0x70, 0x9f, 0xd7, 0x81, 0xb3, 0x58, 0x07, 0xce, 0xdb, - 0x3a, 0x70, 0xee, 0xa3, 0x44, 0x98, 0x71, 0x3e, 0x42, 0x54, 0xa5, 0xd8, 0xa8, 0x07, 0x2e, 0xc5, - 0x23, 0x8f, 0x0a, 0x6c, 0x8a, 0x88, 0x8e, 0x89, 0x90, 0x78, 0x7a, 0x81, 0xed, 0xa6, 0x66, 0xa6, - 0x39, 0x8c, 0xaa, 0xbb, 0x29, 0xcf, 0x3e, 0x03, 0x00, 0x00, 0xff, 0xff, 0xca, 0xf7, 0xa8, 0xea, - 0xbe, 0x01, 0x00, 0x00, + // 372 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x4f, 0x6b, 0xdb, 0x30, + 0x18, 0x87, 0xed, 0x64, 0x04, 0xe2, 0x9d, 0x66, 0xc2, 0x16, 0x87, 0x60, 0x7b, 0xde, 0x61, 0xbe, + 0xd8, 0x22, 0x1b, 0x63, 0xb0, 0x5b, 0xbc, 0x42, 0x4e, 0x85, 0x92, 0xdc, 0x7a, 0x31, 0x8a, 0x2c, + 0x1c, 0xd1, 0x58, 0x12, 0x96, 0x1c, 0x9c, 0x7e, 0x81, 0x5e, 0xfb, 0x61, 0xfa, 0x21, 0x72, 0x0c, + 0x3d, 0xf5, 0x64, 0x8a, 0xf3, 0x0d, 0xf2, 0x09, 0x4a, 0xa2, 0xa4, 0x0d, 0xf4, 0xcf, 0x4d, 0x7a, + 0x9f, 0x87, 0xdf, 0xfb, 0x4a, 0xaf, 0xf1, 0x55, 0x96, 0x80, 0x0b, 0x0c, 0x16, 0x03, 0xc0, 0x61, + 0x0e, 0x33, 0x11, 0xf2, 0x9c, 0x49, 0x66, 0xb6, 0x65, 0x19, 0x72, 0x81, 0xc3, 0xc5, 0xa0, 0x67, + 0x21, 0x26, 0x32, 0x26, 0xe2, 0x3d, 0x00, 0xea, 0xa2, 0xac, 0x5e, 0x27, 0x65, 0x29, 0x53, 0xf5, + 0xdd, 0xe9, 0x50, 0xed, 0xbf, 0x64, 0x26, 0x44, 0xc8, 0x9c, 0x4c, 0x0b, 0x49, 0x18, 0x55, 0xd4, + 0xab, 0x1b, 0x46, 0xeb, 0x62, 0xdf, 0xca, 0x4c, 0x0c, 0x13, 0x97, 0x68, 0x5e, 0x24, 0x38, 0x89, + 0x61, 0x92, 0xe4, 0x58, 0x08, 0x2c, 0xba, 0xba, 0xdb, 0xf4, 0xdb, 0xd1, 0x9f, 0x6d, 0xe5, 0x58, + 0x4b, 0x98, 0xcd, 0xff, 0x79, 0xaf, 0x1d, 0xef, 0xfe, 0x2e, 0xe8, 0x1c, 0x26, 0x19, 0xaa, 0xe2, + 0x44, 0xe6, 0x84, 0xa6, 0xe3, 0x2f, 0x47, 0x79, 0x78, 0x74, 0xcd, 0x1b, 0xdd, 0xb0, 0xd0, 0x1c, + 0xc3, 0x1d, 0x8f, 0x21, 0x42, 0xac, 0xa0, 0x32, 0xce, 0x20, 0xe7, 0x84, 0xa6, 0xa2, 0xdb, 0x70, + 0x9b, 0xfe, 0xe7, 0x5f, 0xdf, 0xc3, 0xe7, 0xf7, 0x86, 0xff, 0x0f, 0xee, 0x50, 0xa9, 0xe7, 0xca, + 0x8c, 0xfc, 0x55, 0xe5, 0x68, 0xdb, 0xca, 0x71, 0xd5, 0x50, 0xef, 0x26, 0x7a, 0xe3, 0x6f, 0xe8, + 0xcd, 0x04, 0x61, 0xce, 0x8c, 0x7e, 0x46, 0x68, 0x7c, 0xfa, 0x29, 0x71, 0x0a, 0x79, 0x2c, 0x30, + 0x62, 0x34, 0x11, 0xdd, 0xa6, 0xab, 0xfb, 0x9f, 0xa2, 0x9f, 0xdb, 0xca, 0xf9, 0xa1, 0x9a, 0x7c, + 0x64, 0x7b, 0x63, 0x2b, 0x23, 0xf4, 0xec, 0x84, 0x8e, 0x20, 0x9f, 0x28, 0x16, 0x8d, 0x56, 0xb5, + 0xad, 0xaf, 0x6b, 0x5b, 0x7f, 0xac, 0x6d, 0xfd, 0x76, 0x63, 0x6b, 0xeb, 0x8d, 0xad, 0x3d, 0x6c, + 0x6c, 0xed, 0x32, 0x48, 0x89, 0x9c, 0x15, 0xd3, 0x10, 0xb1, 0x0c, 0x48, 0x76, 0x85, 0x29, 0xb9, + 0xc6, 0x41, 0x09, 0x64, 0x19, 0xa0, 0x19, 0x24, 0x14, 0x2c, 0xfe, 0x02, 0xb5, 0x3d, 0xb9, 0xe4, + 0x58, 0x4c, 0x5b, 0xfb, 0xa5, 0xfd, 0x7e, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x24, 0xb9, 0x0e, 0x8a, + 0x28, 0x02, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -133,6 +145,11 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.MinDistributionGapSeconds != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.MinDistributionGapSeconds)) + i-- + dAtA[i] = 0x18 + } if len(m.ClearingAccountMappings) > 0 { for iNdEx := len(m.ClearingAccountMappings) - 1; iNdEx >= 0; iNdEx-- { { @@ -188,6 +205,9 @@ func (m *Params) Size() (n int) { n += 1 + l + sovParams(uint64(l)) } } + if m.MinDistributionGapSeconds != 0 { + n += 1 + sovParams(uint64(m.MinDistributionGapSeconds)) + } return n } @@ -292,6 +312,25 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MinDistributionGapSeconds", wireType) + } + m.MinDistributionGapSeconds = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MinDistributionGapSeconds |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) From c5f58e3b38e730a9394fc6f0c2306ad207e092af Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Fri, 20 Feb 2026 10:42:00 +0300 Subject: [PATCH 03/13] add distribution_id and min gap validation to schedule --- x/pse/keeper/distribution.go | 9 +++++++++ x/pse/types/genesis.go | 5 +++++ x/pse/types/params.go | 34 ++++++++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/x/pse/keeper/distribution.go b/x/pse/keeper/distribution.go index 350cc63b..9e9290f6 100644 --- a/x/pse/keeper/distribution.go +++ b/x/pse/keeper/distribution.go @@ -266,6 +266,15 @@ func (k Keeper) UpdateDistributionSchedule( return errorsmod.Wrapf(types.ErrInvalidAuthority, "expected %s, got %s", k.authority, authority) } + // Validate minimum gap between distributions + params, err := k.GetParams(ctx) + if err != nil { + return err + } + if err := types.ValidateDistributionGap(newSchedule, params.MinDistributionGapSeconds); err != nil { + return err + } + // Clear all existing schedule entries if err := k.AllocationSchedule.Clear(ctx, nil); err != nil { return errorsmod.Wrap(err, "failed to clear existing allocation schedule") diff --git a/x/pse/types/genesis.go b/x/pse/types/genesis.go index f7a48b1c..8b99e571 100644 --- a/x/pse/types/genesis.go +++ b/x/pse/types/genesis.go @@ -27,6 +27,11 @@ func (m *GenesisState) Validate() error { return errorsmod.Wrapf(err, "invalid allocation schedule") } + // Validate minimum gap between distributions using the param from genesis state + if err := ValidateDistributionGap(m.ScheduledDistributions, m.Params.MinDistributionGapSeconds); err != nil { + return errorsmod.Wrapf(err, "invalid distribution gap") + } + // Validate delegation time entries for _, delegationTimeEntry := range m.DelegationTimeEntries { if delegationTimeEntry.ValidatorAddress == "" { diff --git a/x/pse/types/params.go b/x/pse/types/params.go index da11c089..565f2217 100644 --- a/x/pse/types/params.go +++ b/x/pse/types/params.go @@ -43,8 +43,9 @@ func GetNonCommunityClearingAccounts() []string { // DefaultParams returns default pse clearing account parameters. func DefaultParams() Params { return Params{ - ExcludedAddresses: []string{}, - ClearingAccountMappings: []ClearingAccountMapping{}, + ExcludedAddresses: []string{}, + ClearingAccountMappings: []ClearingAccountMapping{}, + MinDistributionGapSeconds: uint64(24 * 60 * 60), // 1 day } } @@ -132,14 +133,26 @@ func ValidateDistributionSchedule(schedule []ScheduledDistribution) error { var lastTime uint64 for i, period := range schedule { + // Validate distribution_id is non-zero + if period.DistributionId == 0 { + return errorsmod.Wrapf(ErrInvalidParam, "period %d: distribution_id cannot be zero", i) + } + + // Validate distribution_id is strictly increasing and sequential (each ID = previous + 1). + if i > 0 && period.DistributionId != schedule[i-1].DistributionId+1 { + return errorsmod.Wrapf(ErrInvalidParam, + "period %d: distribution_id must be sequential, expected %d but got %d", + i, schedule[i-1].DistributionId+1, period.DistributionId) + } + // Validate timestamp is not zero if period.Timestamp == 0 { - return errorsmod.Wrapf(ErrInvalidParam, "timestamp cannot be zero") + return errorsmod.Wrapf(ErrInvalidParam, "period %d: timestamp cannot be zero", i) } // Check for duplicate timestamps if seenTimestamps[period.Timestamp] { - return errorsmod.Wrapf(ErrInvalidParam, "duplicate timestamp") + return errorsmod.Wrapf(ErrInvalidParam, "period %d: duplicate timestamp", i) } seenTimestamps[period.Timestamp] = true @@ -227,3 +240,16 @@ func ValidateDistributionSchedule(schedule []ScheduledDistribution) error { return nil } + +// ValidateDistributionGap validates that consecutive distributions have at least minGapSeconds between them. +func ValidateDistributionGap(schedule []ScheduledDistribution, minGapSeconds uint64) error { + for i := 1; i < len(schedule); i++ { + gap := schedule[i].Timestamp - schedule[i-1].Timestamp + if gap < minGapSeconds { + return errorsmod.Wrapf(ErrInvalidParam, + "period %d: minimum gap between distributions is %d seconds, got %d seconds", + i, minGapSeconds, gap) + } + } + return nil +} From 062fac4104f270069d0e869dc6698e5527c8fecf Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Fri, 20 Feb 2026 10:42:58 +0300 Subject: [PATCH 04/13] update tests for distribution_id and min gap validation --- x/pse/keeper/distribution_test.go | 6 +- x/pse/keeper/genesis_test.go | 6 +- x/pse/keeper/msg_server_test.go | 8 ++- x/pse/types/params_test.go | 99 +++++++++++++++++++++++-------- 4 files changed, 86 insertions(+), 33 deletions(-) diff --git a/x/pse/keeper/distribution_test.go b/x/pse/keeper/distribution_test.go index 17ffca1b..5b37e66e 100644 --- a/x/pse/keeper/distribution_test.go +++ b/x/pse/keeper/distribution_test.go @@ -63,7 +63,8 @@ func TestDistribution_GenesisRebuild(t *testing.T) { // Create and store allocation schedule with all clearing accounts schedule := []types.ScheduledDistribution{ { - Timestamp: time1, + DistributionId: 1, + Timestamp: time1, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(5000)}, {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, @@ -74,7 +75,8 @@ func TestDistribution_GenesisRebuild(t *testing.T) { }, }, { - Timestamp: time2, + DistributionId: 2, + Timestamp: time2, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(10000)}, {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(2000)}, diff --git a/x/pse/keeper/genesis_test.go b/x/pse/keeper/genesis_test.go index ff8593e0..f0a75637 100644 --- a/x/pse/keeper/genesis_test.go +++ b/x/pse/keeper/genesis_test.go @@ -136,7 +136,8 @@ func TestGenesis_InvalidState(t *testing.T) { // Only include 4 accounts, missing Community and Team gs.ScheduledDistributions = []types.ScheduledDistribution{ { - Timestamp: now, + DistributionId: 1, + Timestamp: now, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, {ClearingAccount: types.ClearingAccountAlliance, Amount: sdkmath.NewInt(200)}, @@ -155,7 +156,8 @@ func TestGenesis_InvalidState(t *testing.T) { // Include only non-Community accounts, missing Community gs.ScheduledDistributions = []types.ScheduledDistribution{ { - Timestamp: now, + DistributionId: 1, + Timestamp: now, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, {ClearingAccount: types.ClearingAccountAlliance, Amount: sdkmath.NewInt(200)}, diff --git a/x/pse/keeper/msg_server_test.go b/x/pse/keeper/msg_server_test.go index b0f18941..36ac4de2 100644 --- a/x/pse/keeper/msg_server_test.go +++ b/x/pse/keeper/msg_server_test.go @@ -182,8 +182,9 @@ func TestMsgUpdateAllocationSchedule(t *testing.T) { baseTimestamp := uint64(1700000000) // Some future timestamp for i := range numPeriods { schedule[i] = types.ScheduledDistribution{ - Timestamp: baseTimestamp + uint64(i*86400), // One day apart - Allocations: createAllAllocations(amount), + DistributionId: uint64(i + 1), + Timestamp: baseTimestamp + uint64(i*86400), // One day apart + Allocations: createAllAllocations(amount), } } return schedule @@ -225,7 +226,8 @@ func TestMsgUpdateAllocationSchedule(t *testing.T) { Authority: authority, Schedule: []types.ScheduledDistribution{ { - Timestamp: uint64(1700000000), + DistributionId: 1, + Timestamp: uint64(1700000000), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(1000000)}, {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(2000000)}, diff --git a/x/pse/types/params_test.go b/x/pse/types/params_test.go index d16e3c26..7c8ca6d7 100644 --- a/x/pse/types/params_test.go +++ b/x/pse/types/params_test.go @@ -313,8 +313,9 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "valid_single_period", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), - Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), + DistributionId: 1, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, }, expectErr: false, @@ -323,12 +324,14 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "valid_multiple_periods_sorted", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), - Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), + DistributionId: 1, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, { - Timestamp: getTestTimestamp(12), - Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), + DistributionId: 2, + Timestamp: getTestTimestamp(12), + Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, }, expectErr: false, @@ -337,7 +340,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "valid_with_community_account", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), + DistributionId: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ // All clearing accounts (including Community) should be in schedule {ClearingAccount: ClearingAccountCommunity, Amount: sdkmath.NewInt(5000)}, @@ -351,11 +355,41 @@ func TestValidateAllocationSchedule(t *testing.T) { }, expectErr: false, }, + { + name: "invalid_zero_distribution_id", + schedule: []ScheduledDistribution{ + { + DistributionId: 0, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), + }, + }, + expectErr: true, + errMsg: "distribution_id cannot be zero", + }, + { + name: "invalid_non_sequential_distribution_id", + schedule: []ScheduledDistribution{ + { + DistributionId: 1, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), + }, + { + DistributionId: 5, + Timestamp: getTestTimestamp(12), + Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), + }, + }, + expectErr: true, + errMsg: "distribution_id must be sequential", + }, { name: "invalid_zero_timestamp", schedule: []ScheduledDistribution{ { - Timestamp: 0, + DistributionId: 1, + Timestamp: 0, Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, }, @@ -368,12 +402,14 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_duplicate_timestamp", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), - Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), + DistributionId: 1, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, { - Timestamp: getTestTimestamp(0), - Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), + DistributionId: 2, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, }, expectErr: true, @@ -383,12 +419,14 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_unsorted_schedule", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(12), - Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), + DistributionId: 1, + Timestamp: getTestTimestamp(12), + Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, { - Timestamp: getTestTimestamp(0), - Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), + DistributionId: 2, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, }, expectErr: true, @@ -398,8 +436,9 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_empty_allocations_array", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), - Allocations: []ClearingAccountAllocation{}, + DistributionId: 1, + Timestamp: getTestTimestamp(0), + Allocations: []ClearingAccountAllocation{}, }, }, expectErr: true, @@ -409,7 +448,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_too_few_allocations", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), + DistributionId: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, }, @@ -422,7 +462,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_empty_clearing_account", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), + DistributionId: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: "", Amount: sdkmath.NewInt(1000)}, {ClearingAccount: ClearingAccountAlliance, Amount: sdkmath.NewInt(1000)}, @@ -439,7 +480,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_unknown_clearing_account", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), + DistributionId: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: "unknown_module", Amount: sdkmath.NewInt(1000)}, {ClearingAccount: ClearingAccountCommunity, Amount: sdkmath.NewInt(1000)}, @@ -458,7 +500,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_duplicate_clearing_account_in_period", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), + DistributionId: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(2000)}, // Duplicate @@ -476,7 +519,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_missing_clearing_account", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), + DistributionId: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, {ClearingAccount: ClearingAccountAlliance, Amount: sdkmath.NewInt(1000)}, @@ -493,7 +537,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_nil_amount", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), + DistributionId: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.Int{}}, {ClearingAccount: ClearingAccountAlliance, Amount: sdkmath.NewInt(1000)}, @@ -510,7 +555,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_negative_amount", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), + DistributionId: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(-1000)}, {ClearingAccount: ClearingAccountAlliance, Amount: sdkmath.NewInt(1000)}, @@ -527,7 +573,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_zero_amount", schedule: []ScheduledDistribution{ { - Timestamp: getTestTimestamp(0), + DistributionId: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.ZeroInt()}, {ClearingAccount: ClearingAccountAlliance, Amount: sdkmath.NewInt(1000)}, From d7125fa414a736ed0aa574665bf3547dfff31a44 Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Fri, 20 Feb 2026 13:02:29 +0300 Subject: [PATCH 05/13] change AllocationSchedule store key from timestamp to distributionID --- integration-tests/modules/pse_test.go | 6 +++--- x/pse/keeper/distribution.go | 18 +++++++++--------- x/pse/keeper/distribution_test.go | 8 +++++--- x/pse/keeper/genesis.go | 4 ++-- x/pse/keeper/grpc_query_test.go | 24 +++++++++++++++--------- x/pse/keeper/keeper.go | 2 +- 6 files changed, 35 insertions(+), 27 deletions(-) diff --git a/integration-tests/modules/pse_test.go b/integration-tests/modules/pse_test.go index 10887ce1..bc24d984 100644 --- a/integration-tests/modules/pse_test.go +++ b/integration-tests/modules/pse_test.go @@ -213,9 +213,9 @@ func TestPSEDistribution(t *testing.T) { &psetypes.MsgUpdateDistributionSchedule{ Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), Schedule: []psetypes.ScheduledDistribution{ - {Timestamp: uint64(distributionStartTime.Add(30 * time.Second).Unix()), Allocations: allocations}, - {Timestamp: uint64(distributionStartTime.Add(60 * time.Second).Unix()), Allocations: allocations}, - {Timestamp: uint64(distributionStartTime.Add(90 * time.Second).Unix()), Allocations: allocations}, + {DistributionId: 1, Timestamp: uint64(distributionStartTime.Add(30 * time.Second).Unix()), Allocations: allocations}, + {DistributionId: 2, Timestamp: uint64(distributionStartTime.Add(60 * time.Second).Unix()), Allocations: allocations}, + {DistributionId: 3, Timestamp: uint64(distributionStartTime.Add(90 * time.Second).Unix()), Allocations: allocations}, }, }, &psetypes.MsgUpdateClearingAccountMappings{ diff --git a/x/pse/keeper/distribution.go b/x/pse/keeper/distribution.go index 9e9290f6..73dfb0fc 100644 --- a/x/pse/keeper/distribution.go +++ b/x/pse/keeper/distribution.go @@ -50,7 +50,7 @@ func (k Keeper) ProcessNextDistribution(ctx context.Context) error { } // Remove the completed distribution from the schedule - if err := k.AllocationSchedule.Remove(ctx, timestamp); err != nil { + if err := k.AllocationSchedule.Remove(ctx, scheduledDistribution.DistributionId); err != nil { return err } @@ -76,18 +76,18 @@ func (k Keeper) PeekNextAllocationSchedule(ctx context.Context) (types.Scheduled return types.ScheduledDistribution{}, false, nil } - // Extract the earliest scheduled distribution + // Extract the earliest scheduled distribution (sorted by distributionID ascending) kv, err := iter.KeyValue() if err != nil { return types.ScheduledDistribution{}, false, err } - timestamp := kv.Key scheduledDist := kv.Value // Check if distribution time has arrived - // Since the map is sorted by timestamp, if the first item is in the future, all items are - shouldProcess := timestamp <= uint64(sdkCtx.BlockTime().Unix()) + // Since distributionIDs are sequential and timestamps are monotonically increasing, + // the first item by ID is also the earliest by time. + shouldProcess := scheduledDist.Timestamp <= uint64(sdkCtx.BlockTime().Unix()) return scheduledDist, shouldProcess, nil } @@ -220,15 +220,15 @@ func (k Keeper) distributeAllocatedTokens( // Each scheduled distribution is stored in the AllocationSchedule map, indexed by its timestamp. func (k Keeper) SaveDistributionSchedule(ctx context.Context, schedule []types.ScheduledDistribution) error { for _, scheduledDist := range schedule { - if err := k.AllocationSchedule.Set(ctx, scheduledDist.Timestamp, scheduledDist); err != nil { - return errorsmod.Wrapf(err, "failed to save distribution at timestamp %d", scheduledDist.Timestamp) + if err := k.AllocationSchedule.Set(ctx, scheduledDist.DistributionId, scheduledDist); err != nil { + return errorsmod.Wrapf(err, "failed to save distribution with id %d", scheduledDist.DistributionId) } } return nil } // GetDistributionSchedule returns the complete allocation schedule as a sorted list. -// The schedule is sorted by timestamp in ascending order. +// The schedule is sorted by distributionID in ascending order. // Returns an empty slice if no allocations are scheduled. // Note: Past schedule allocations removed after processing, so this only contains future schedule allocations. func (k Keeper) GetDistributionSchedule(ctx context.Context) ([]types.ScheduledDistribution, error) { @@ -248,7 +248,7 @@ func (k Keeper) GetDistributionSchedule(ctx context.Context) ([]types.ScheduledD schedule = append(schedule, kv.Value) } - // Note: Collections map iterates in ascending order of keys (timestamps), + // Note: Collections map iterates in ascending order of keys (distributionIDs), // so the schedule is already sorted. No need to sort again. return schedule, nil } diff --git a/x/pse/keeper/distribution_test.go b/x/pse/keeper/distribution_test.go index 5b37e66e..78780077 100644 --- a/x/pse/keeper/distribution_test.go +++ b/x/pse/keeper/distribution_test.go @@ -90,7 +90,7 @@ func TestDistribution_GenesisRebuild(t *testing.T) { // Store in allocation schedule map for _, scheduledDist := range schedule { - err = pseKeeper.AllocationSchedule.Set(ctx, scheduledDist.Timestamp, scheduledDist) + err = pseKeeper.AllocationSchedule.Set(ctx, scheduledDist.DistributionId, scheduledDist) requireT.NoError(err) } @@ -185,7 +185,8 @@ func TestDistribution_PrecisionWithMultipleRecipients(t *testing.T) { startTime := uint64(time.Now().Add(-1 * time.Hour).Unix()) schedule := []types.ScheduledDistribution{ { - Timestamp: startTime, + DistributionId: 1, + Timestamp: startTime, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: allocationAmount}, {ClearingAccount: types.ClearingAccountAlliance, Amount: allocationAmount}, @@ -316,7 +317,8 @@ func TestDistribution_EndBlockFailure(t *testing.T) { startTime := uint64(time.Now().Add(-1 * time.Hour).Unix()) schedule := []types.ScheduledDistribution{ { - Timestamp: startTime, + DistributionId: 1, + Timestamp: startTime, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: allocationAmount}, {ClearingAccount: types.ClearingAccountAlliance, Amount: allocationAmount}, diff --git a/x/pse/keeper/genesis.go b/x/pse/keeper/genesis.go index 977f7336..4ae76b89 100644 --- a/x/pse/keeper/genesis.go +++ b/x/pse/keeper/genesis.go @@ -23,7 +23,7 @@ func (k Keeper) InitGenesis(ctx context.Context, genState types.GenesisState) er // Populate allocation schedule from genesis state for _, scheduledDist := range genState.ScheduledDistributions { - if err := k.AllocationSchedule.Set(ctx, scheduledDist.Timestamp, scheduledDist); err != nil { + if err := k.AllocationSchedule.Set(ctx, scheduledDist.DistributionId, scheduledDist); err != nil { return err } } @@ -70,7 +70,7 @@ func (k Keeper) ExportGenesis(ctx context.Context) (*types.GenesisState, error) return nil, err } - // Export allocation schedule using keeper method (already sorted by timestamp) + // Export allocation schedule using keeper method (already sorted by distributionID) genesis.ScheduledDistributions, err = k.GetDistributionSchedule(ctx) if err != nil { return nil, err diff --git a/x/pse/keeper/grpc_query_test.go b/x/pse/keeper/grpc_query_test.go index 42111114..ee8e20e8 100644 --- a/x/pse/keeper/grpc_query_test.go +++ b/x/pse/keeper/grpc_query_test.go @@ -285,13 +285,15 @@ func TestQueryAllocationSchedule(t *testing.T) { // Create schedule allocations at different future times schedule1 := types.ScheduledDistribution{ - Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), + DistributionId: 1, + Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(2000)}, }, } schedule2 := types.ScheduledDistribution{ - Timestamp: uint64(currentTime.Add(2 * time.Hour).Unix()), + DistributionId: 2, + Timestamp: uint64(currentTime.Add(2 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountTeam, Amount: sdkmath.NewInt(3000)}, }, @@ -315,7 +317,8 @@ func TestQueryAllocationSchedule(t *testing.T) { queryService := keeper.NewQueryService(testApp.PSEKeeper) schedule := types.ScheduledDistribution{ - Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), + DistributionId: 1, + Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(1000)}, {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(2000)}, @@ -332,28 +335,31 @@ func TestQueryAllocationSchedule(t *testing.T) { requireT.Len(resp.ScheduledDistributions[0].Allocations, 3) }) - t.Run("schedule sorted by timestamp", func(t *testing.T) { + t.Run("schedule sorted by distributionID", func(t *testing.T) { requireT := require.New(t) testApp := simapp.New() currentTime := time.Now() ctx := testApp.NewContext(false).WithBlockTime(currentTime) queryService := keeper.NewQueryService(testApp.PSEKeeper) - // Save schedule item in non-chronological order + // Save schedule items in non-sequential order of distributionID schedule3 := types.ScheduledDistribution{ - Timestamp: uint64(currentTime.Add(3 * time.Hour).Unix()), + DistributionId: 3, + Timestamp: uint64(currentTime.Add(3 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountAlliance, Amount: sdkmath.NewInt(3000)}, }, } schedule1 := types.ScheduledDistribution{ - Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), + DistributionId: 1, + Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountPartnership, Amount: sdkmath.NewInt(1000)}, }, } schedule2 := types.ScheduledDistribution{ - Timestamp: uint64(currentTime.Add(2 * time.Hour).Unix()), + DistributionId: 2, + Timestamp: uint64(currentTime.Add(2 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountInvestors, Amount: sdkmath.NewInt(2000)}, }, @@ -365,7 +371,7 @@ func TestQueryAllocationSchedule(t *testing.T) { resp, err := queryService.ScheduledDistributions(ctx, &types.QueryScheduledDistributionsRequest{}) requireT.NoError(err) requireT.Len(resp.ScheduledDistributions, 3) - // Verify schedule are sorted by timestamp in ascending order + // Verify schedule items are sorted by distributionID in ascending order requireT.Equal(schedule1.Timestamp, resp.ScheduledDistributions[0].Timestamp) requireT.Equal(schedule2.Timestamp, resp.ScheduledDistributions[1].Timestamp) requireT.Equal(schedule3.Timestamp, resp.ScheduledDistributions[2].Timestamp) diff --git a/x/pse/keeper/keeper.go b/x/pse/keeper/keeper.go index eb075c32..770266eb 100644 --- a/x/pse/keeper/keeper.go +++ b/x/pse/keeper/keeper.go @@ -34,7 +34,7 @@ type Keeper struct { Params collections.Item[types.Params] DelegationTimeEntries collections.Map[collections.Pair[sdk.AccAddress, sdk.ValAddress], types.DelegationTimeEntry] AccountScoreSnapshot collections.Map[sdk.AccAddress, sdkmath.Int] - AllocationSchedule collections.Map[uint64, types.ScheduledDistribution] // Map: timestamp -> ScheduledDistribution + AllocationSchedule collections.Map[uint64, types.ScheduledDistribution] // Map: distributionID -> ScheduledDistribution DistributionDisabled collections.Item[bool] } From 48f276248bbe2caee59472ff39d3f8013e083242 Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Fri, 20 Feb 2026 13:34:51 +0300 Subject: [PATCH 06/13] rename distribution_id to id --- docs/api.md | 4 +- docs/static/openapi.json | 6 +- integration-tests/modules/pse_test.go | 6 +- proto/tx/pse/v1/distribution.proto | 8 +-- x/pse/keeper/distribution.go | 16 ++--- x/pse/keeper/distribution_test.go | 10 ++-- x/pse/keeper/genesis.go | 4 +- x/pse/keeper/genesis_test.go | 4 +- x/pse/keeper/grpc_query_test.go | 18 +++--- x/pse/keeper/keeper.go | 2 +- x/pse/keeper/msg_server_test.go | 4 +- x/pse/types/distribution.pb.go | 85 +++++++++++++-------------- x/pse/types/params.go | 14 ++--- x/pse/types/params_test.go | 50 ++++++++-------- 14 files changed, 115 insertions(+), 116 deletions(-) diff --git a/docs/api.md b/docs/api.md index 41effa84..0cd78038 100644 --- a/docs/api.md +++ b/docs/api.md @@ -5818,7 +5818,7 @@ During distribution, the allocated amount is split equally among all recipients. ``` ScheduledDistribution defines a single allocation event at a specific timestamp. Multiple clearing accounts can allocate tokens at the same time. -Each distribution is identified by a unique, sequential distribution_id. +Each distribution is identified by a unique, sequential id. ``` @@ -5827,7 +5827,7 @@ Each distribution is identified by a unique, sequential distribution_id. | ----- | ---- | ----- | ----------- | | `timestamp` | [uint64](#uint64) | | `timestamp is when this allocation should occur (Unix timestamp in seconds).` | | `allocations` | [ClearingAccountAllocation](#tx.pse.v1.ClearingAccountAllocation) | repeated | `allocations is the list of amounts to allocate from each clearing account at this time.` | -| `distribution_id` | [uint64](#uint64) | | `distribution_id is the unique, sequential identifier for this distribution. Used as the storage key in the AllocationSchedule map.` | +| `id` | [uint64](#uint64) | | `id is the unique, sequential identifier for this distribution. Used as the storage key in the AllocationSchedule map.` | diff --git a/docs/static/openapi.json b/docs/static/openapi.json index fa222086..301d272d 100644 --- a/docs/static/openapi.json +++ b/docs/static/openapi.json @@ -16880,13 +16880,13 @@ }, "description": "allocations is the list of amounts to allocate from each clearing account at this time." }, - "distribution_id": { + "id": { "type": "string", "format": "uint64", - "description": "distribution_id is the unique, sequential identifier for this distribution.\nUsed as the storage key in the AllocationSchedule map." + "description": "id is the unique, sequential identifier for this distribution.\nUsed as the storage key in the AllocationSchedule map." } }, - "description": "ScheduledDistribution defines a single allocation event at a specific timestamp.\nMultiple clearing accounts can allocate tokens at the same time.\nEach distribution is identified by a unique, sequential distribution_id." + "description": "ScheduledDistribution defines a single allocation event at a specific timestamp.\nMultiple clearing accounts can allocate tokens at the same time.\nEach distribution is identified by a unique, sequential id." } } } diff --git a/integration-tests/modules/pse_test.go b/integration-tests/modules/pse_test.go index bc24d984..7e4061af 100644 --- a/integration-tests/modules/pse_test.go +++ b/integration-tests/modules/pse_test.go @@ -213,9 +213,9 @@ func TestPSEDistribution(t *testing.T) { &psetypes.MsgUpdateDistributionSchedule{ Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), Schedule: []psetypes.ScheduledDistribution{ - {DistributionId: 1, Timestamp: uint64(distributionStartTime.Add(30 * time.Second).Unix()), Allocations: allocations}, - {DistributionId: 2, Timestamp: uint64(distributionStartTime.Add(60 * time.Second).Unix()), Allocations: allocations}, - {DistributionId: 3, Timestamp: uint64(distributionStartTime.Add(90 * time.Second).Unix()), Allocations: allocations}, + {Id: 1, Timestamp: uint64(distributionStartTime.Add(30 * time.Second).Unix()), Allocations: allocations}, + {Id: 2, Timestamp: uint64(distributionStartTime.Add(60 * time.Second).Unix()), Allocations: allocations}, + {Id: 3, Timestamp: uint64(distributionStartTime.Add(90 * time.Second).Unix()), Allocations: allocations}, }, }, &psetypes.MsgUpdateClearingAccountMappings{ diff --git a/proto/tx/pse/v1/distribution.proto b/proto/tx/pse/v1/distribution.proto index 17add0ee..12e4d96b 100644 --- a/proto/tx/pse/v1/distribution.proto +++ b/proto/tx/pse/v1/distribution.proto @@ -43,7 +43,7 @@ message ClearingAccountAllocation { // ScheduledDistribution defines a single allocation event at a specific timestamp. // Multiple clearing accounts can allocate tokens at the same time. -// Each distribution is identified by a unique, sequential distribution_id. +// Each distribution is identified by a unique, sequential id. message ScheduledDistribution { // timestamp is when this allocation should occur (Unix timestamp in seconds). uint64 timestamp = 1 [ @@ -56,10 +56,10 @@ message ScheduledDistribution { (gogoproto.moretags) = "yaml:\"allocations\"" ]; - // distribution_id is the unique, sequential identifier for this distribution. + // id is the unique, sequential identifier for this distribution. // Used as the storage key in the AllocationSchedule map. - uint64 distribution_id = 3 [ - (gogoproto.moretags) = "yaml:\"distribution_id\"" + uint64 id = 3 [ + (gogoproto.moretags) = "yaml:\"id\"" ]; } diff --git a/x/pse/keeper/distribution.go b/x/pse/keeper/distribution.go index 73dfb0fc..65ecdbd0 100644 --- a/x/pse/keeper/distribution.go +++ b/x/pse/keeper/distribution.go @@ -50,7 +50,7 @@ func (k Keeper) ProcessNextDistribution(ctx context.Context) error { } // Remove the completed distribution from the schedule - if err := k.AllocationSchedule.Remove(ctx, scheduledDistribution.DistributionId); err != nil { + if err := k.AllocationSchedule.Remove(ctx, scheduledDistribution.Id); err != nil { return err } @@ -76,7 +76,7 @@ func (k Keeper) PeekNextAllocationSchedule(ctx context.Context) (types.Scheduled return types.ScheduledDistribution{}, false, nil } - // Extract the earliest scheduled distribution (sorted by distributionID ascending) + // Extract the earliest scheduled distribution (sorted by id ascending) kv, err := iter.KeyValue() if err != nil { return types.ScheduledDistribution{}, false, err @@ -85,7 +85,7 @@ func (k Keeper) PeekNextAllocationSchedule(ctx context.Context) (types.Scheduled scheduledDist := kv.Value // Check if distribution time has arrived - // Since distributionIDs are sequential and timestamps are monotonically increasing, + // Since IDs are sequential and timestamps are monotonically increasing, // the first item by ID is also the earliest by time. shouldProcess := scheduledDist.Timestamp <= uint64(sdkCtx.BlockTime().Unix()) @@ -217,18 +217,18 @@ func (k Keeper) distributeAllocatedTokens( } // SaveDistributionSchedule persists the distribution schedule to blockchain state. -// Each scheduled distribution is stored in the AllocationSchedule map, indexed by its timestamp. +// Each scheduled distribution is stored in the AllocationSchedule map, indexed by its ID. func (k Keeper) SaveDistributionSchedule(ctx context.Context, schedule []types.ScheduledDistribution) error { for _, scheduledDist := range schedule { - if err := k.AllocationSchedule.Set(ctx, scheduledDist.DistributionId, scheduledDist); err != nil { - return errorsmod.Wrapf(err, "failed to save distribution with id %d", scheduledDist.DistributionId) + if err := k.AllocationSchedule.Set(ctx, scheduledDist.Id, scheduledDist); err != nil { + return errorsmod.Wrapf(err, "failed to save distribution with id %d", scheduledDist.Id) } } return nil } // GetDistributionSchedule returns the complete allocation schedule as a sorted list. -// The schedule is sorted by distributionID in ascending order. +// The schedule is sorted by id in ascending order. // Returns an empty slice if no allocations are scheduled. // Note: Past schedule allocations removed after processing, so this only contains future schedule allocations. func (k Keeper) GetDistributionSchedule(ctx context.Context) ([]types.ScheduledDistribution, error) { @@ -248,7 +248,7 @@ func (k Keeper) GetDistributionSchedule(ctx context.Context) ([]types.ScheduledD schedule = append(schedule, kv.Value) } - // Note: Collections map iterates in ascending order of keys (distributionIDs), + // Note: Collections map iterates in ascending order of keys (IDs), // so the schedule is already sorted. No need to sort again. return schedule, nil } diff --git a/x/pse/keeper/distribution_test.go b/x/pse/keeper/distribution_test.go index 78780077..2dfc98b3 100644 --- a/x/pse/keeper/distribution_test.go +++ b/x/pse/keeper/distribution_test.go @@ -63,7 +63,7 @@ func TestDistribution_GenesisRebuild(t *testing.T) { // Create and store allocation schedule with all clearing accounts schedule := []types.ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: time1, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(5000)}, @@ -75,7 +75,7 @@ func TestDistribution_GenesisRebuild(t *testing.T) { }, }, { - DistributionId: 2, + Id: 2, Timestamp: time2, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(10000)}, @@ -90,7 +90,7 @@ func TestDistribution_GenesisRebuild(t *testing.T) { // Store in allocation schedule map for _, scheduledDist := range schedule { - err = pseKeeper.AllocationSchedule.Set(ctx, scheduledDist.DistributionId, scheduledDist) + err = pseKeeper.AllocationSchedule.Set(ctx, scheduledDist.Id, scheduledDist) requireT.NoError(err) } @@ -185,7 +185,7 @@ func TestDistribution_PrecisionWithMultipleRecipients(t *testing.T) { startTime := uint64(time.Now().Add(-1 * time.Hour).Unix()) schedule := []types.ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: startTime, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: allocationAmount}, @@ -317,7 +317,7 @@ func TestDistribution_EndBlockFailure(t *testing.T) { startTime := uint64(time.Now().Add(-1 * time.Hour).Unix()) schedule := []types.ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: startTime, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: allocationAmount}, diff --git a/x/pse/keeper/genesis.go b/x/pse/keeper/genesis.go index 4ae76b89..b8acbbf9 100644 --- a/x/pse/keeper/genesis.go +++ b/x/pse/keeper/genesis.go @@ -23,7 +23,7 @@ func (k Keeper) InitGenesis(ctx context.Context, genState types.GenesisState) er // Populate allocation schedule from genesis state for _, scheduledDist := range genState.ScheduledDistributions { - if err := k.AllocationSchedule.Set(ctx, scheduledDist.DistributionId, scheduledDist); err != nil { + if err := k.AllocationSchedule.Set(ctx, scheduledDist.Id, scheduledDist); err != nil { return err } } @@ -70,7 +70,7 @@ func (k Keeper) ExportGenesis(ctx context.Context) (*types.GenesisState, error) return nil, err } - // Export allocation schedule using keeper method (already sorted by distributionID) + // Export allocation schedule using keeper method (already sorted by id) genesis.ScheduledDistributions, err = k.GetDistributionSchedule(ctx) if err != nil { return nil, err diff --git a/x/pse/keeper/genesis_test.go b/x/pse/keeper/genesis_test.go index f0a75637..0459d09f 100644 --- a/x/pse/keeper/genesis_test.go +++ b/x/pse/keeper/genesis_test.go @@ -136,7 +136,7 @@ func TestGenesis_InvalidState(t *testing.T) { // Only include 4 accounts, missing Community and Team gs.ScheduledDistributions = []types.ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: now, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, @@ -156,7 +156,7 @@ func TestGenesis_InvalidState(t *testing.T) { // Include only non-Community accounts, missing Community gs.ScheduledDistributions = []types.ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: now, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, diff --git a/x/pse/keeper/grpc_query_test.go b/x/pse/keeper/grpc_query_test.go index ee8e20e8..899df624 100644 --- a/x/pse/keeper/grpc_query_test.go +++ b/x/pse/keeper/grpc_query_test.go @@ -285,14 +285,14 @@ func TestQueryAllocationSchedule(t *testing.T) { // Create schedule allocations at different future times schedule1 := types.ScheduledDistribution{ - DistributionId: 1, + Id: 1, Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(2000)}, }, } schedule2 := types.ScheduledDistribution{ - DistributionId: 2, + Id: 2, Timestamp: uint64(currentTime.Add(2 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountTeam, Amount: sdkmath.NewInt(3000)}, @@ -317,7 +317,7 @@ func TestQueryAllocationSchedule(t *testing.T) { queryService := keeper.NewQueryService(testApp.PSEKeeper) schedule := types.ScheduledDistribution{ - DistributionId: 1, + Id: 1, Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(1000)}, @@ -335,30 +335,30 @@ func TestQueryAllocationSchedule(t *testing.T) { requireT.Len(resp.ScheduledDistributions[0].Allocations, 3) }) - t.Run("schedule sorted by distributionID", func(t *testing.T) { + t.Run("schedule sorted by id", func(t *testing.T) { requireT := require.New(t) testApp := simapp.New() currentTime := time.Now() ctx := testApp.NewContext(false).WithBlockTime(currentTime) queryService := keeper.NewQueryService(testApp.PSEKeeper) - // Save schedule items in non-sequential order of distributionID + // Save schedule items in non-sequential order of id schedule3 := types.ScheduledDistribution{ - DistributionId: 3, + Id: 3, Timestamp: uint64(currentTime.Add(3 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountAlliance, Amount: sdkmath.NewInt(3000)}, }, } schedule1 := types.ScheduledDistribution{ - DistributionId: 1, + Id: 1, Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountPartnership, Amount: sdkmath.NewInt(1000)}, }, } schedule2 := types.ScheduledDistribution{ - DistributionId: 2, + Id: 2, Timestamp: uint64(currentTime.Add(2 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountInvestors, Amount: sdkmath.NewInt(2000)}, @@ -371,7 +371,7 @@ func TestQueryAllocationSchedule(t *testing.T) { resp, err := queryService.ScheduledDistributions(ctx, &types.QueryScheduledDistributionsRequest{}) requireT.NoError(err) requireT.Len(resp.ScheduledDistributions, 3) - // Verify schedule items are sorted by distributionID in ascending order + // Verify schedule items are sorted by id in ascending order requireT.Equal(schedule1.Timestamp, resp.ScheduledDistributions[0].Timestamp) requireT.Equal(schedule2.Timestamp, resp.ScheduledDistributions[1].Timestamp) requireT.Equal(schedule3.Timestamp, resp.ScheduledDistributions[2].Timestamp) diff --git a/x/pse/keeper/keeper.go b/x/pse/keeper/keeper.go index 770266eb..a572aed9 100644 --- a/x/pse/keeper/keeper.go +++ b/x/pse/keeper/keeper.go @@ -34,7 +34,7 @@ type Keeper struct { Params collections.Item[types.Params] DelegationTimeEntries collections.Map[collections.Pair[sdk.AccAddress, sdk.ValAddress], types.DelegationTimeEntry] AccountScoreSnapshot collections.Map[sdk.AccAddress, sdkmath.Int] - AllocationSchedule collections.Map[uint64, types.ScheduledDistribution] // Map: distributionID -> ScheduledDistribution + AllocationSchedule collections.Map[uint64, types.ScheduledDistribution] // Map: id -> ScheduledDistribution DistributionDisabled collections.Item[bool] } diff --git a/x/pse/keeper/msg_server_test.go b/x/pse/keeper/msg_server_test.go index 36ac4de2..ef5f42ae 100644 --- a/x/pse/keeper/msg_server_test.go +++ b/x/pse/keeper/msg_server_test.go @@ -182,7 +182,7 @@ func TestMsgUpdateAllocationSchedule(t *testing.T) { baseTimestamp := uint64(1700000000) // Some future timestamp for i := range numPeriods { schedule[i] = types.ScheduledDistribution{ - DistributionId: uint64(i + 1), + Id: uint64(i + 1), Timestamp: baseTimestamp + uint64(i*86400), // One day apart Allocations: createAllAllocations(amount), } @@ -226,7 +226,7 @@ func TestMsgUpdateAllocationSchedule(t *testing.T) { Authority: authority, Schedule: []types.ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: uint64(1700000000), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(1000000)}, diff --git a/x/pse/types/distribution.pb.go b/x/pse/types/distribution.pb.go index b3732429..271d33a9 100644 --- a/x/pse/types/distribution.pb.go +++ b/x/pse/types/distribution.pb.go @@ -135,15 +135,15 @@ func (m *ClearingAccountAllocation) GetClearingAccount() string { // ScheduledDistribution defines a single allocation event at a specific timestamp. // Multiple clearing accounts can allocate tokens at the same time. -// Each distribution is identified by a unique, sequential distribution_id. +// Each distribution is identified by a unique, sequential id. type ScheduledDistribution struct { // timestamp is when this allocation should occur (Unix timestamp in seconds). Timestamp uint64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty" yaml:"timestamp"` // allocations is the list of amounts to allocate from each clearing account at this time. Allocations []ClearingAccountAllocation `protobuf:"bytes,2,rep,name=allocations,proto3" json:"allocations" yaml:"allocations"` - // distribution_id is the unique, sequential identifier for this distribution. + // id is the unique, sequential identifier for this distribution. // Used as the storage key in the AllocationSchedule map. - DistributionId uint64 `protobuf:"varint,3,opt,name=distribution_id,json=distributionId,proto3" json:"distribution_id,omitempty" yaml:"distribution_id"` + Id uint64 `protobuf:"varint,3,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` } func (m *ScheduledDistribution) Reset() { *m = ScheduledDistribution{} } @@ -193,9 +193,9 @@ func (m *ScheduledDistribution) GetAllocations() []ClearingAccountAllocation { return nil } -func (m *ScheduledDistribution) GetDistributionId() uint64 { +func (m *ScheduledDistribution) GetId() uint64 { if m != nil { - return m.DistributionId + return m.Id } return 0 } @@ -209,37 +209,36 @@ func init() { func init() { proto.RegisterFile("tx/pse/v1/distribution.proto", fileDescriptor_a549fe743b42ab69) } var fileDescriptor_a549fe743b42ab69 = []byte{ - // 466 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0xbf, 0x6e, 0xd3, 0x40, - 0x18, 0x8f, 0x5b, 0x54, 0x29, 0x57, 0x41, 0x2b, 0x93, 0x96, 0xd4, 0x20, 0xbb, 0xb2, 0x18, 0xba, - 0xc4, 0xa7, 0x16, 0x09, 0x24, 0xc4, 0x12, 0x17, 0x81, 0x32, 0xb0, 0xb8, 0x4c, 0x2c, 0xd1, 0xe5, - 0x7c, 0x72, 0x4e, 0xb5, 0xef, 0x2c, 0xdf, 0x97, 0x28, 0xe5, 0x29, 0x78, 0x18, 0x16, 0xde, 0xa0, - 0x6c, 0x15, 0x13, 0x62, 0x38, 0xa1, 0xe4, 0x0d, 0x2c, 0x1e, 0x00, 0xd9, 0x67, 0x39, 0x21, 0x82, - 0x8d, 0xcd, 0xfe, 0x7e, 0x7f, 0xf4, 0xfb, 0x7d, 0xfe, 0x8c, 0x9e, 0xc0, 0x02, 0xe7, 0x8a, 0xe1, - 0xf9, 0x39, 0x8e, 0xb9, 0x82, 0x82, 0x4f, 0x66, 0xc0, 0xa5, 0x08, 0xf2, 0x42, 0x82, 0xb4, 0xbb, - 0xb0, 0x08, 0x72, 0xc5, 0x82, 0xf9, 0xb9, 0xd3, 0x4b, 0x64, 0x22, 0xeb, 0x29, 0xae, 0x9e, 0x0c, - 0xc1, 0x39, 0xa1, 0x52, 0x65, 0x52, 0x8d, 0x0d, 0x60, 0x5e, 0x0c, 0xe4, 0x7f, 0xb5, 0xd0, 0xf1, - 0x65, 0xca, 0x48, 0xc1, 0x45, 0x32, 0xa4, 0x54, 0xce, 0x04, 0xbc, 0x23, 0x79, 0xce, 0x45, 0x62, - 0xbf, 0x41, 0x87, 0xb4, 0x41, 0xc6, 0xc4, 0x40, 0x7d, 0xeb, 0xd4, 0x3a, 0xeb, 0x86, 0x8f, 0x4b, - 0xed, 0x3d, 0xba, 0x21, 0x59, 0xfa, 0xd2, 0xdf, 0x66, 0xf8, 0xd1, 0x01, 0xfd, 0xd3, 0xce, 0x4e, - 0xd0, 0xc3, 0x82, 0x51, 0x9e, 0x73, 0x26, 0x60, 0x4c, 0xe2, 0xb8, 0x60, 0x4a, 0x31, 0xd5, 0xdf, - 0x39, 0xdd, 0x3d, 0xeb, 0x86, 0xcf, 0x4b, 0xed, 0x39, 0xc6, 0xea, 0x2f, 0x24, 0xff, 0xdb, 0xe7, - 0x41, 0xaf, 0xc9, 0x3b, 0x34, 0xc3, 0x2b, 0xa8, 0xbc, 0x23, 0xbb, 0x65, 0x0f, 0x5b, 0xf2, 0x17, - 0x0b, 0x9d, 0x6c, 0x75, 0x19, 0xa6, 0xa9, 0xa4, 0xa4, 0xda, 0xd5, 0x7f, 0xab, 0xf3, 0x1e, 0xed, - 0x91, 0xac, 0x56, 0xef, 0xd4, 0xea, 0x57, 0xb7, 0xda, 0xeb, 0xfc, 0xd0, 0xde, 0x91, 0xc9, 0xa9, - 0xe2, 0xeb, 0x80, 0x4b, 0x9c, 0x11, 0x98, 0x06, 0x23, 0x01, 0xa5, 0xf6, 0xee, 0x1b, 0x6b, 0x23, - 0xaa, 0x1a, 0xa1, 0xa6, 0xd1, 0x48, 0x40, 0xd4, 0x78, 0xf9, 0xbf, 0x2c, 0x74, 0x74, 0x45, 0xa7, - 0x2c, 0x9e, 0xa5, 0x2c, 0x7e, 0xbd, 0xf1, 0x8d, 0xed, 0x0b, 0xd4, 0x05, 0x9e, 0x31, 0x05, 0x24, - 0xcb, 0xeb, 0xc0, 0xf7, 0xc2, 0x5e, 0xa9, 0xbd, 0x43, 0xe3, 0xda, 0x42, 0x7e, 0xb4, 0xa6, 0xd9, - 0x13, 0xb4, 0x4f, 0xda, 0xe6, 0x66, 0xd5, 0xfb, 0x17, 0x4f, 0x83, 0xf6, 0x4e, 0x82, 0x7f, 0xae, - 0x29, 0x74, 0xaa, 0x3a, 0xa5, 0xf6, 0xec, 0x26, 0xf5, 0xda, 0xc6, 0x8f, 0x36, 0x4d, 0xed, 0x4b, - 0x74, 0xb0, 0x79, 0x8b, 0x63, 0x1e, 0xf7, 0x77, 0xeb, 0x74, 0x4e, 0xa9, 0xbd, 0x63, 0xa3, 0xde, - 0x22, 0xf8, 0xd1, 0x83, 0xcd, 0xc9, 0x28, 0x0e, 0xdf, 0xde, 0x2e, 0x5d, 0xeb, 0x6e, 0xe9, 0x5a, - 0x3f, 0x97, 0xae, 0xf5, 0x69, 0xe5, 0x76, 0xee, 0x56, 0x6e, 0xe7, 0xfb, 0xca, 0xed, 0x7c, 0x18, - 0x24, 0x1c, 0xa6, 0xb3, 0x49, 0x40, 0x65, 0x86, 0x41, 0x5e, 0x33, 0xc1, 0x3f, 0xb2, 0xc1, 0x02, - 0xc3, 0x62, 0x40, 0xa7, 0x84, 0x0b, 0x3c, 0x7f, 0x81, 0xcd, 0x3f, 0x01, 0x37, 0x39, 0x53, 0x93, - 0xbd, 0xfa, 0x9c, 0x9f, 0xfd, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x8c, 0x50, 0x13, 0x8c, 0x2a, 0x03, - 0x00, 0x00, + // 459 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0xcf, 0x6a, 0xd4, 0x40, + 0x18, 0xdf, 0x6c, 0xa5, 0x90, 0x29, 0xc5, 0x12, 0xb7, 0xba, 0x5d, 0x35, 0x29, 0xc1, 0x43, 0x2f, + 0x9b, 0xa1, 0x15, 0x14, 0xc4, 0xcb, 0x46, 0x51, 0x7a, 0xf0, 0x92, 0x7a, 0xf2, 0xb2, 0xcc, 0xce, + 0x0c, 0xd9, 0xa1, 0xc9, 0x4c, 0xc8, 0x7c, 0xbb, 0x6c, 0x7d, 0x0a, 0x1f, 0xc6, 0x8b, 0x6f, 0x50, + 0x2f, 0x52, 0x3c, 0x89, 0x87, 0x41, 0x76, 0xdf, 0x20, 0x4f, 0x20, 0xc9, 0x84, 0xb4, 0x16, 0xbd, + 0x79, 0x4b, 0xbe, 0xdf, 0x1f, 0x7e, 0xbf, 0x6f, 0x3e, 0xf4, 0x08, 0x56, 0xb8, 0xd0, 0x1c, 0x2f, + 0x8f, 0x31, 0x13, 0x1a, 0x4a, 0x31, 0x5b, 0x80, 0x50, 0x32, 0x2a, 0x4a, 0x05, 0xca, 0x73, 0x61, + 0x15, 0x15, 0x9a, 0x47, 0xcb, 0xe3, 0xd1, 0x20, 0x55, 0xa9, 0x6a, 0xa6, 0xb8, 0xfe, 0xb2, 0x84, + 0xd1, 0x01, 0x55, 0x3a, 0x57, 0x7a, 0x6a, 0x01, 0xfb, 0x63, 0xa1, 0xf0, 0xab, 0x83, 0xee, 0xbf, + 0xca, 0x38, 0x29, 0x85, 0x4c, 0x27, 0x94, 0xaa, 0x85, 0x84, 0x77, 0xa4, 0x28, 0x84, 0x4c, 0xbd, + 0x37, 0x68, 0x8f, 0xb6, 0xc8, 0x94, 0x58, 0x68, 0xe8, 0x1c, 0x3a, 0x47, 0x6e, 0xfc, 0xb0, 0x32, + 0xc1, 0x83, 0x0b, 0x92, 0x67, 0x2f, 0xc2, 0xdb, 0x8c, 0x30, 0xb9, 0x4b, 0xff, 0xb4, 0xf3, 0x52, + 0x74, 0xaf, 0xe4, 0x54, 0x14, 0x82, 0x4b, 0x98, 0x12, 0xc6, 0x4a, 0xae, 0x35, 0xd7, 0xc3, 0xfe, + 0xe1, 0xd6, 0x91, 0x1b, 0x3f, 0xab, 0x4c, 0x30, 0xb2, 0x56, 0x7f, 0x21, 0x85, 0xdf, 0x3f, 0x8f, + 0x07, 0x6d, 0xde, 0x89, 0x1d, 0x9e, 0x41, 0xed, 0x9d, 0x78, 0x1d, 0x7b, 0xd2, 0x91, 0xbf, 0x38, + 0xe8, 0xe0, 0x56, 0x97, 0x49, 0x96, 0x29, 0x4a, 0xea, 0x5d, 0xfd, 0xb7, 0x3a, 0xef, 0xd1, 0x36, + 0xc9, 0x1b, 0x75, 0xbf, 0x51, 0xbf, 0xbc, 0x34, 0x41, 0xef, 0xa7, 0x09, 0xf6, 0x6d, 0x4e, 0xcd, + 0xce, 0x23, 0xa1, 0x70, 0x4e, 0x60, 0x1e, 0x9d, 0x4a, 0xa8, 0x4c, 0xb0, 0x6b, 0xad, 0xad, 0xa8, + 0x6e, 0x84, 0xda, 0x46, 0xa7, 0x12, 0x92, 0xd6, 0x2b, 0xfc, 0xe6, 0xa0, 0xfd, 0x33, 0x3a, 0xe7, + 0x6c, 0x91, 0x71, 0xf6, 0xfa, 0xc6, 0x1b, 0x7b, 0x27, 0xc8, 0x05, 0x91, 0x73, 0x0d, 0x24, 0x2f, + 0x9a, 0xc0, 0x77, 0xe2, 0x41, 0x65, 0x82, 0x3d, 0xeb, 0xda, 0x41, 0x61, 0x72, 0x4d, 0xf3, 0x66, + 0x68, 0x87, 0x74, 0xcd, 0xed, 0xaa, 0x77, 0x4e, 0x9e, 0x44, 0xdd, 0x9d, 0x44, 0xff, 0x5c, 0x53, + 0x3c, 0xaa, 0xeb, 0x54, 0x26, 0xf0, 0xda, 0xd4, 0xd7, 0x36, 0x61, 0x72, 0xd3, 0xd4, 0x7b, 0x8c, + 0xfa, 0x82, 0x0d, 0xb7, 0x9a, 0x40, 0xbb, 0x95, 0x09, 0x5c, 0x2b, 0x10, 0x2c, 0x4c, 0xfa, 0x82, + 0xc5, 0x6f, 0x2f, 0xd7, 0xbe, 0x73, 0xb5, 0xf6, 0x9d, 0x5f, 0x6b, 0xdf, 0xf9, 0xb4, 0xf1, 0x7b, + 0x57, 0x1b, 0xbf, 0xf7, 0x63, 0xe3, 0xf7, 0x3e, 0x8c, 0x53, 0x01, 0xf3, 0xc5, 0x2c, 0xa2, 0x2a, + 0xc7, 0xa0, 0xce, 0xb9, 0x14, 0x1f, 0xf9, 0x78, 0x85, 0x61, 0x35, 0xa6, 0x73, 0x22, 0x24, 0x5e, + 0x3e, 0xc7, 0xf6, 0xda, 0xe1, 0xa2, 0xe0, 0x7a, 0xb6, 0xdd, 0x1c, 0xea, 0xd3, 0xdf, 0x01, 0x00, + 0x00, 0xff, 0xff, 0xaf, 0x42, 0x2e, 0x00, 0x04, 0x03, 0x00, 0x00, } func (m *ClearingAccountMapping) Marshal() (dAtA []byte, err error) { @@ -341,8 +340,8 @@ func (m *ScheduledDistribution) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.DistributionId != 0 { - i = encodeVarintDistribution(dAtA, i, uint64(m.DistributionId)) + if m.Id != 0 { + i = encodeVarintDistribution(dAtA, i, uint64(m.Id)) i-- dAtA[i] = 0x18 } @@ -428,8 +427,8 @@ func (m *ScheduledDistribution) Size() (n int) { n += 1 + l + sovDistribution(uint64(l)) } } - if m.DistributionId != 0 { - n += 1 + sovDistribution(uint64(m.DistributionId)) + if m.Id != 0 { + n += 1 + sovDistribution(uint64(m.Id)) } return n } @@ -754,9 +753,9 @@ func (m *ScheduledDistribution) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 3: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field DistributionId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) } - m.DistributionId = 0 + m.Id = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowDistribution @@ -766,7 +765,7 @@ func (m *ScheduledDistribution) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.DistributionId |= uint64(b&0x7F) << shift + m.Id |= uint64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/pse/types/params.go b/x/pse/types/params.go index 565f2217..657818f8 100644 --- a/x/pse/types/params.go +++ b/x/pse/types/params.go @@ -133,16 +133,16 @@ func ValidateDistributionSchedule(schedule []ScheduledDistribution) error { var lastTime uint64 for i, period := range schedule { - // Validate distribution_id is non-zero - if period.DistributionId == 0 { - return errorsmod.Wrapf(ErrInvalidParam, "period %d: distribution_id cannot be zero", i) + // Validate id is non-zero + if period.Id == 0 { + return errorsmod.Wrapf(ErrInvalidParam, "period %d: id cannot be zero", i) } - // Validate distribution_id is strictly increasing and sequential (each ID = previous + 1). - if i > 0 && period.DistributionId != schedule[i-1].DistributionId+1 { + // Validate id is strictly increasing and sequential (each ID = previous + 1). + if i > 0 && period.Id != schedule[i-1].Id+1 { return errorsmod.Wrapf(ErrInvalidParam, - "period %d: distribution_id must be sequential, expected %d but got %d", - i, schedule[i-1].DistributionId+1, period.DistributionId) + "period %d: id must be sequential, expected %d but got %d", + i, schedule[i-1].Id+1, period.Id) } // Validate timestamp is not zero diff --git a/x/pse/types/params_test.go b/x/pse/types/params_test.go index 7c8ca6d7..8ccff664 100644 --- a/x/pse/types/params_test.go +++ b/x/pse/types/params_test.go @@ -313,7 +313,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "valid_single_period", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, @@ -324,12 +324,12 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "valid_multiple_periods_sorted", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, { - DistributionId: 2, + Id: 2, Timestamp: getTestTimestamp(12), Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, @@ -340,7 +340,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "valid_with_community_account", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ // All clearing accounts (including Community) should be in schedule @@ -356,39 +356,39 @@ func TestValidateAllocationSchedule(t *testing.T) { expectErr: false, }, { - name: "invalid_zero_distribution_id", + name: "invalid_zero_id", schedule: []ScheduledDistribution{ { - DistributionId: 0, + Id: 0, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, }, expectErr: true, - errMsg: "distribution_id cannot be zero", + errMsg: "id cannot be zero", }, { - name: "invalid_non_sequential_distribution_id", + name: "invalid_non_sequential_id", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, { - DistributionId: 5, + Id: 5, Timestamp: getTestTimestamp(12), Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, }, expectErr: true, - errMsg: "distribution_id must be sequential", + errMsg: "id must be sequential", }, { name: "invalid_zero_timestamp", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: 0, Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, @@ -402,12 +402,12 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_duplicate_timestamp", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, { - DistributionId: 2, + Id: 2, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, @@ -419,12 +419,12 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_unsorted_schedule", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(12), Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, { - DistributionId: 2, + Id: 2, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, @@ -436,7 +436,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_empty_allocations_array", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{}, }, @@ -448,7 +448,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_too_few_allocations", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, @@ -462,7 +462,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_empty_clearing_account", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: "", Amount: sdkmath.NewInt(1000)}, @@ -480,7 +480,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_unknown_clearing_account", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: "unknown_module", Amount: sdkmath.NewInt(1000)}, @@ -500,7 +500,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_duplicate_clearing_account_in_period", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, @@ -519,7 +519,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_missing_clearing_account", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, @@ -537,7 +537,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_nil_amount", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.Int{}}, @@ -555,7 +555,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_negative_amount", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(-1000)}, @@ -573,7 +573,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_zero_amount", schedule: []ScheduledDistribution{ { - DistributionId: 1, + Id: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.ZeroInt()}, From ba38c8e18c44bb5b349b6d592759ecaa1180d7c5 Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Mon, 23 Feb 2026 10:49:03 +0300 Subject: [PATCH 07/13] fix readme & comment --- x/pse/keeper/distribution.go | 2 +- x/pse/spec/README.md | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/x/pse/keeper/distribution.go b/x/pse/keeper/distribution.go index 65ecdbd0..f4578712 100644 --- a/x/pse/keeper/distribution.go +++ b/x/pse/keeper/distribution.go @@ -64,7 +64,7 @@ func (k Keeper) ProcessNextDistribution(ctx context.Context) error { func (k Keeper) PeekNextAllocationSchedule(ctx context.Context) (types.ScheduledDistribution, bool, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) - // Get iterator for the allocation schedule (sorted by timestamp ascending) + // Get iterator for the allocation schedule (sorted by id ascending) iter, err := k.AllocationSchedule.Iterate(ctx, nil) if err != nil { return types.ScheduledDistribution{}, false, err diff --git a/x/pse/spec/README.md b/x/pse/spec/README.md index 54e92bee..a255ec46 100644 --- a/x/pse/spec/README.md +++ b/x/pse/spec/README.md @@ -126,7 +126,7 @@ State managed by the PSE module: - **Params**: `0x00 | -> Params` - **DelegationTimeEntries**: `0x01 | delegator_address | validator_address -> DelegationTimeEntry` - **AccountScoreSnapshot**: `0x02 | delegator_address -> Int` -- **AllocationSchedule**: `0x03 | timestamp (uint64) -> ScheduledDistribution` +- **AllocationSchedule**: `0x03 | id (uint64) -> ScheduledDistribution` ### Params @@ -134,6 +134,7 @@ Module parameters containing: - `ExcludedAddresses`: List of addresses excluded from Community distributions - `ClearingAccountMappings`: Recipient address mappings for non-Community clearing accounts +- `MinDistributionGapSeconds`: Minimum time gap (in seconds) between consecutive scheduled distributions (default: 86400 = 1 day) ### DelegationTimeEntry @@ -155,12 +156,13 @@ Stores the accumulated score for each delegator address over the current 1-month ### AllocationSchedule -Maps timestamps to scheduled distributions: +Maps distribution IDs to scheduled distributions: ```protobuf message ScheduledDistribution { uint64 timestamp = 1; // Unix timestamp when distribution should occur repeated ClearingAccountAllocation allocations = 2; // Allocations for each clearing account + uint64 id = 3; // Unique, sequential identifier (storage key) } message ClearingAccountAllocation { From 2e2b5c67dea0bdb6e3dc3789465b80d62df6a47a Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Mon, 23 Feb 2026 12:43:25 +0300 Subject: [PATCH 08/13] add MsgUpdateMinDistributionGap governance message --- docs/api.md | 24 +++ proto/tx/pse/v1/tx.proto | 19 ++ x/deterministicgas/config.go | 1 + x/pse/keeper/distribution.go | 29 +++ x/pse/keeper/msg_server.go | 16 ++ x/pse/keeper/msg_server_test.go | 119 +++++++++++- x/pse/types/tx.pb.go | 333 ++++++++++++++++++++++++++++---- 7 files changed, 496 insertions(+), 45 deletions(-) diff --git a/docs/api.md b/docs/api.md index 0cd78038..370ba537 100644 --- a/docs/api.md +++ b/docs/api.md @@ -311,6 +311,7 @@ - [MsgUpdateClearingAccountMappings](#tx.pse.v1.MsgUpdateClearingAccountMappings) - [MsgUpdateDistributionSchedule](#tx.pse.v1.MsgUpdateDistributionSchedule) - [MsgUpdateExcludedAddresses](#tx.pse.v1.MsgUpdateExcludedAddresses) + - [MsgUpdateMinDistributionGap](#tx.pse.v1.MsgUpdateMinDistributionGap) - [Msg](#tx.pse.v1.Msg) @@ -6330,6 +6331,28 @@ All existing distributions are removed and replaced with the provided distributi + + + +### MsgUpdateMinDistributionGap + +``` +MsgUpdateMinDistributionGap is a governance operation to update the minimum time gap +between consecutive scheduled distributions. The new gap is validated against the +existing on-chain schedule to ensure consistency. +``` + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `authority` | [string](#string) | | `authority is the address authorized to update the gap (governance module address).` | +| `min_distribution_gap_seconds` | [uint64](#uint64) | | `min_distribution_gap_seconds is the minimum time gap (in seconds) between consecutive distributions.` | + + + + + @@ -6352,6 +6375,7 @@ Msg defines the Msg service. | `UpdateClearingAccountMappings` | [MsgUpdateClearingAccountMappings](#tx.pse.v1.MsgUpdateClearingAccountMappings) | [EmptyResponse](#tx.pse.v1.EmptyResponse) | `UpdateClearingAccountMappings is a governance operation to update clearing account to recipient mappings.` | | | `UpdateDistributionSchedule` | [MsgUpdateDistributionSchedule](#tx.pse.v1.MsgUpdateDistributionSchedule) | [EmptyResponse](#tx.pse.v1.EmptyResponse) | `UpdateDistributionSchedule is a governance operation to update the distribution schedule.` | | | `DisableDistributions` | [MsgDisableDistributions](#tx.pse.v1.MsgDisableDistributions) | [EmptyResponse](#tx.pse.v1.EmptyResponse) | `DisableDistributions is a governance operation to disable distributions.` | | +| `UpdateMinDistributionGap` | [MsgUpdateMinDistributionGap](#tx.pse.v1.MsgUpdateMinDistributionGap) | [EmptyResponse](#tx.pse.v1.EmptyResponse) | `UpdateMinDistributionGap is a governance operation to update the minimum gap between distributions.` | | diff --git a/proto/tx/pse/v1/tx.proto b/proto/tx/pse/v1/tx.proto index 42311ab2..e1a0d8dc 100644 --- a/proto/tx/pse/v1/tx.proto +++ b/proto/tx/pse/v1/tx.proto @@ -24,6 +24,9 @@ service Msg { // DisableDistributions is a governance operation to disable distributions. rpc DisableDistributions(MsgDisableDistributions) returns (EmptyResponse); + + // UpdateMinDistributionGap is a governance operation to update the minimum gap between distributions. + rpc UpdateMinDistributionGap(MsgUpdateMinDistributionGap) returns (EmptyResponse); } message MsgDisableDistributions { @@ -90,4 +93,20 @@ message MsgUpdateDistributionSchedule { ]; } +// MsgUpdateMinDistributionGap is a governance operation to update the minimum time gap +// between consecutive scheduled distributions. The new gap is validated against the +// existing on-chain schedule to ensure consistency. +message MsgUpdateMinDistributionGap { + option (cosmos.msg.v1.signer) = "authority"; + option (amino.name) = "pse/MsgUpdateMinDistributionGap"; + + // authority is the address authorized to update the gap (governance module address). + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // min_distribution_gap_seconds is the minimum time gap (in seconds) between consecutive distributions. + uint64 min_distribution_gap_seconds = 2 [ + (gogoproto.moretags) = "yaml:\"min_distribution_gap_seconds\"" + ]; +} + message EmptyResponse {} diff --git a/x/deterministicgas/config.go b/x/deterministicgas/config.go index 5a795666..4bd10566 100644 --- a/x/deterministicgas/config.go +++ b/x/deterministicgas/config.go @@ -239,6 +239,7 @@ func DefaultConfig() Config { &psetypes.MsgUpdateClearingAccountMappings{}, &psetypes.MsgUpdateDistributionSchedule{}, &psetypes.MsgDisableDistributions{}, + &psetypes.MsgUpdateMinDistributionGap{}, // distribution &distributiontypes.MsgUpdateParams{}, // This is non-deterministic because all the gov proposals are non-deterministic anyway diff --git a/x/pse/keeper/distribution.go b/x/pse/keeper/distribution.go index f4578712..9124922e 100644 --- a/x/pse/keeper/distribution.go +++ b/x/pse/keeper/distribution.go @@ -284,6 +284,35 @@ func (k Keeper) UpdateDistributionSchedule( return k.SaveDistributionSchedule(ctx, newSchedule) } +// UpdateMinDistributionGap updates the minimum time gap between distributions via governance. +// The new gap is validated against the existing on-chain schedule to ensure consistency. +func (k Keeper) UpdateMinDistributionGap( + ctx context.Context, + authority string, + minGapSeconds uint64, +) error { + if k.authority != authority { + return errorsmod.Wrapf(types.ErrInvalidAuthority, "expected %s, got %s", k.authority, authority) + } + + // Validate new gap against existing schedule + schedule, err := k.GetDistributionSchedule(ctx) + if err != nil { + return err + } + if err := types.ValidateDistributionGap(schedule, minGapSeconds); err != nil { + return errorsmod.Wrapf(err, "existing schedule violates proposed min gap of %d seconds", minGapSeconds) + } + + // Update params + params, err := k.GetParams(ctx) + if err != nil { + return err + } + params.MinDistributionGapSeconds = minGapSeconds + return k.SetParams(ctx, params) +} + // DisableDistributions is a governance operation that disables distributions. func (k Keeper) DisableDistributions(ctx context.Context, authority string) error { // Check authority diff --git a/x/pse/keeper/msg_server.go b/x/pse/keeper/msg_server.go index 16052c02..11a63f67 100644 --- a/x/pse/keeper/msg_server.go +++ b/x/pse/keeper/msg_server.go @@ -69,6 +69,22 @@ func (ms MsgServer) UpdateDistributionSchedule( return &types.EmptyResponse{}, nil } +// UpdateMinDistributionGap is a governance operation that updates the minimum distribution gap. +func (ms MsgServer) UpdateMinDistributionGap( + goCtx context.Context, + req *types.MsgUpdateMinDistributionGap, +) (*types.EmptyResponse, error) { + err := ms.keeper.UpdateMinDistributionGap( + goCtx, + req.Authority, + req.MinDistributionGapSeconds, + ) + if err != nil { + return nil, err + } + return &types.EmptyResponse{}, nil +} + // DisableDistributions is a governance operation that disables distributions. func (ms MsgServer) DisableDistributions( goCtx context.Context, diff --git a/x/pse/keeper/msg_server_test.go b/x/pse/keeper/msg_server_test.go index ef5f42ae..1d42e114 100644 --- a/x/pse/keeper/msg_server_test.go +++ b/x/pse/keeper/msg_server_test.go @@ -182,9 +182,9 @@ func TestMsgUpdateAllocationSchedule(t *testing.T) { baseTimestamp := uint64(1700000000) // Some future timestamp for i := range numPeriods { schedule[i] = types.ScheduledDistribution{ - Id: uint64(i + 1), - Timestamp: baseTimestamp + uint64(i*86400), // One day apart - Allocations: createAllAllocations(amount), + Id: uint64(i + 1), + Timestamp: baseTimestamp + uint64(i*86400), // One day apart + Allocations: createAllAllocations(amount), } } return schedule @@ -226,8 +226,8 @@ func TestMsgUpdateAllocationSchedule(t *testing.T) { Authority: authority, Schedule: []types.ScheduledDistribution{ { - Id: 1, - Timestamp: uint64(1700000000), + Id: 1, + Timestamp: uint64(1700000000), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(1000000)}, {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(2000000)}, @@ -299,3 +299,112 @@ func TestMsgUpdateAllocationSchedule(t *testing.T) { }) } } + +func TestMsgUpdateMinDistributionGap(t *testing.T) { + requireT := require.New(t) + + testApp := simapp.New() + ctx := testApp.NewContext(false) + msgServer := keeper.NewMsgServer(testApp.PSEKeeper) + + authority := authtypes.NewModuleAddress(govtypes.ModuleName).String() + invalidAuthority := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()).String() + + // Set up a schedule with 1-day gaps + baseTimestamp := uint64(1700000000) + daySeconds := uint64(86400) + schedule := []types.ScheduledDistribution{ + { + Id: 1, + Timestamp: baseTimestamp, + Allocations: []types.ClearingAccountAllocation{ + {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(1000)}, + {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, + {ClearingAccount: types.ClearingAccountAlliance, Amount: sdkmath.NewInt(1000)}, + {ClearingAccount: types.ClearingAccountPartnership, Amount: sdkmath.NewInt(1000)}, + {ClearingAccount: types.ClearingAccountInvestors, Amount: sdkmath.NewInt(1000)}, + {ClearingAccount: types.ClearingAccountTeam, Amount: sdkmath.NewInt(1000)}, + }, + }, + { + Id: 2, + Timestamp: baseTimestamp + daySeconds, // 1 day later + Allocations: []types.ClearingAccountAllocation{ + {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(1000)}, + {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, + {ClearingAccount: types.ClearingAccountAlliance, Amount: sdkmath.NewInt(1000)}, + {ClearingAccount: types.ClearingAccountPartnership, Amount: sdkmath.NewInt(1000)}, + {ClearingAccount: types.ClearingAccountInvestors, Amount: sdkmath.NewInt(1000)}, + {ClearingAccount: types.ClearingAccountTeam, Amount: sdkmath.NewInt(1000)}, + }, + }, + } + + // Save schedule directly + err := testApp.PSEKeeper.SaveDistributionSchedule(ctx, schedule) + requireT.NoError(err) + + t.Run("valid - set gap less than existing interval", func(t *testing.T) { + resp, err := msgServer.UpdateMinDistributionGap(ctx, &types.MsgUpdateMinDistributionGap{ + Authority: authority, + MinDistributionGapSeconds: daySeconds / 2, // 12 hours, schedule has 1-day gaps + }) + requireT.NoError(err) + requireT.NotNil(resp) + + // Verify param was updated + params, err := testApp.PSEKeeper.GetParams(ctx) + requireT.NoError(err) + requireT.Equal(daySeconds/2, params.MinDistributionGapSeconds) + }) + + t.Run("valid - set gap equal to existing interval", func(t *testing.T) { + resp, err := msgServer.UpdateMinDistributionGap(ctx, &types.MsgUpdateMinDistributionGap{ + Authority: authority, + MinDistributionGapSeconds: daySeconds, // exactly 1 day (matches schedule) + }) + requireT.NoError(err) + requireT.NotNil(resp) + + params, err := testApp.PSEKeeper.GetParams(ctx) + requireT.NoError(err) + requireT.Equal(daySeconds, params.MinDistributionGapSeconds) + }) + + t.Run("invalid - gap larger than existing schedule interval", func(t *testing.T) { + resp, err := msgServer.UpdateMinDistributionGap(ctx, &types.MsgUpdateMinDistributionGap{ + Authority: authority, + MinDistributionGapSeconds: daySeconds * 2, // 2 days, but schedule has 1-day gaps + }) + requireT.Error(err) + requireT.Nil(resp) + requireT.Contains(err.Error(), "existing schedule violates proposed min gap") + }) + + t.Run("invalid - wrong authority", func(t *testing.T) { + resp, err := msgServer.UpdateMinDistributionGap(ctx, &types.MsgUpdateMinDistributionGap{ + Authority: invalidAuthority, + MinDistributionGapSeconds: daySeconds / 2, + }) + requireT.Error(err) + requireT.Nil(resp) + requireT.Contains(err.Error(), "invalid authority") + }) + + t.Run("valid - zero gap with empty schedule", func(t *testing.T) { + // Clear schedule + err := testApp.PSEKeeper.AllocationSchedule.Clear(ctx, nil) + requireT.NoError(err) + + resp, err := msgServer.UpdateMinDistributionGap(ctx, &types.MsgUpdateMinDistributionGap{ + Authority: authority, + MinDistributionGapSeconds: 0, + }) + requireT.NoError(err) + requireT.NotNil(resp) + + params, err := testApp.PSEKeeper.GetParams(ctx) + requireT.NoError(err) + requireT.Equal(uint64(0), params.MinDistributionGapSeconds) + }) +} diff --git a/x/pse/types/tx.pb.go b/x/pse/types/tx.pb.go index 6f1c133b..f5755205 100644 --- a/x/pse/types/tx.pb.go +++ b/x/pse/types/tx.pb.go @@ -254,6 +254,63 @@ func (m *MsgUpdateDistributionSchedule) GetSchedule() []ScheduledDistribution { return nil } +// MsgUpdateMinDistributionGap is a governance operation to update the minimum time gap +// between consecutive scheduled distributions. The new gap is validated against the +// existing on-chain schedule to ensure consistency. +type MsgUpdateMinDistributionGap struct { + // authority is the address authorized to update the gap (governance module address). + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // min_distribution_gap_seconds is the minimum time gap (in seconds) between consecutive distributions. + MinDistributionGapSeconds uint64 `protobuf:"varint,2,opt,name=min_distribution_gap_seconds,json=minDistributionGapSeconds,proto3" json:"min_distribution_gap_seconds,omitempty" yaml:"min_distribution_gap_seconds"` +} + +func (m *MsgUpdateMinDistributionGap) Reset() { *m = MsgUpdateMinDistributionGap{} } +func (m *MsgUpdateMinDistributionGap) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateMinDistributionGap) ProtoMessage() {} +func (*MsgUpdateMinDistributionGap) Descriptor() ([]byte, []int) { + return fileDescriptor_7fbcd921f59054cd, []int{4} +} +func (m *MsgUpdateMinDistributionGap) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateMinDistributionGap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateMinDistributionGap.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 *MsgUpdateMinDistributionGap) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateMinDistributionGap.Merge(m, src) +} +func (m *MsgUpdateMinDistributionGap) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateMinDistributionGap) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateMinDistributionGap.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateMinDistributionGap proto.InternalMessageInfo + +func (m *MsgUpdateMinDistributionGap) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpdateMinDistributionGap) GetMinDistributionGapSeconds() uint64 { + if m != nil { + return m.MinDistributionGapSeconds + } + return 0 +} + type EmptyResponse struct { } @@ -261,7 +318,7 @@ func (m *EmptyResponse) Reset() { *m = EmptyResponse{} } func (m *EmptyResponse) String() string { return proto.CompactTextString(m) } func (*EmptyResponse) ProtoMessage() {} func (*EmptyResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_7fbcd921f59054cd, []int{4} + return fileDescriptor_7fbcd921f59054cd, []int{5} } func (m *EmptyResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -295,51 +352,57 @@ func init() { proto.RegisterType((*MsgUpdateExcludedAddresses)(nil), "tx.pse.v1.MsgUpdateExcludedAddresses") proto.RegisterType((*MsgUpdateClearingAccountMappings)(nil), "tx.pse.v1.MsgUpdateClearingAccountMappings") proto.RegisterType((*MsgUpdateDistributionSchedule)(nil), "tx.pse.v1.MsgUpdateDistributionSchedule") + proto.RegisterType((*MsgUpdateMinDistributionGap)(nil), "tx.pse.v1.MsgUpdateMinDistributionGap") proto.RegisterType((*EmptyResponse)(nil), "tx.pse.v1.EmptyResponse") } func init() { proto.RegisterFile("tx/pse/v1/tx.proto", fileDescriptor_7fbcd921f59054cd) } var fileDescriptor_7fbcd921f59054cd = []byte{ - // 605 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0x31, 0x6f, 0xda, 0x40, - 0x18, 0x86, 0x71, 0x50, 0xab, 0x70, 0x55, 0x9b, 0xc6, 0x45, 0x82, 0xba, 0x8d, 0x21, 0x56, 0x2b, - 0x21, 0x2a, 0x6c, 0x91, 0x54, 0x89, 0xc4, 0x06, 0x4d, 0xd4, 0x89, 0x85, 0x24, 0x1d, 0x22, 0x55, - 0xd4, 0xf8, 0x2e, 0xe6, 0x54, 0xec, 0xb3, 0x7c, 0x67, 0x04, 0x9d, 0xda, 0x4e, 0x55, 0xa7, 0xfe, - 0x14, 0x86, 0xfe, 0x88, 0x4c, 0x55, 0xd4, 0xa9, 0x13, 0xaa, 0xa0, 0x12, 0x43, 0x37, 0x7e, 0x41, - 0x84, 0x6d, 0x8c, 0x09, 0x36, 0x03, 0x0b, 0xba, 0xe3, 0x7b, 0xef, 0x7d, 0xee, 0xfd, 0xf8, 0x38, - 0xc0, 0xb3, 0x9e, 0x62, 0x51, 0xa4, 0x74, 0xcb, 0x0a, 0xeb, 0xc9, 0x96, 0x4d, 0x18, 0xe1, 0x53, - 0xb3, 0x15, 0x45, 0x72, 0xb7, 0x2c, 0xec, 0xaa, 0x06, 0x36, 0x89, 0xe2, 0x7e, 0x7a, 0x55, 0x21, - 0xad, 0x13, 0x9d, 0xb8, 0x4b, 0x65, 0xb6, 0xf2, 0xbf, 0x7d, 0xaa, 0x11, 0x6a, 0x10, 0xda, 0xf4, - 0x0a, 0xde, 0xc6, 0x2f, 0x65, 0xbc, 0x9d, 0x62, 0x50, 0x7d, 0x86, 0x31, 0xa8, 0xee, 0x17, 0x9e, - 0x2f, 0xd8, 0x10, 0x53, 0x66, 0xe3, 0x96, 0xc3, 0x30, 0x31, 0xbd, 0xaa, 0xf4, 0x85, 0x03, 0x99, - 0x3a, 0xd5, 0x4f, 0x30, 0x55, 0x5b, 0x1d, 0x74, 0x12, 0x12, 0x50, 0xfe, 0x08, 0xa4, 0x54, 0x87, - 0xb5, 0x89, 0x8d, 0x59, 0x3f, 0xcb, 0xe5, 0xb9, 0x42, 0xaa, 0x96, 0xfd, 0xfd, 0xb3, 0x94, 0xf6, - 0xb9, 0x55, 0x08, 0x6d, 0x44, 0xe9, 0x19, 0xb3, 0xb1, 0xa9, 0x37, 0x16, 0xd2, 0x8a, 0xfc, 0x75, - 0x32, 0x28, 0x2e, 0xf6, 0xdf, 0x27, 0x83, 0xe2, 0xb3, 0xd9, 0x0d, 0x62, 0x38, 0xd2, 0xaf, 0x2d, - 0x20, 0xd4, 0xa9, 0x7e, 0x61, 0x41, 0x95, 0xa1, 0xd3, 0x9e, 0xd6, 0x71, 0x20, 0x82, 0xbe, 0x3b, - 0xda, 0xf8, 0x1a, 0xfc, 0x7b, 0xf0, 0x58, 0x9d, 0x9b, 0x34, 0x19, 0x69, 0xaa, 0x10, 0x66, 0xb7, - 0xf2, 0xc9, 0x42, 0xaa, 0x76, 0x38, 0x1d, 0xe6, 0x32, 0x7d, 0xd5, 0xe8, 0x54, 0xa4, 0xbb, 0x0a, - 0x29, 0xd6, 0xf9, 0x51, 0x20, 0x3d, 0x27, 0x55, 0x08, 0xf9, 0x2b, 0xf0, 0x64, 0xe9, 0xb0, 0x8d, - 0x0c, 0xd2, 0x45, 0xd9, 0xa4, 0x4b, 0x38, 0x9a, 0x0e, 0x73, 0x42, 0x04, 0xc1, 0x13, 0xc5, 0x43, - 0x76, 0x43, 0x90, 0x86, 0xab, 0xad, 0x94, 0x57, 0xbb, 0x29, 0xfa, 0xdd, 0x8c, 0xe9, 0x98, 0xf4, - 0x9f, 0x03, 0xf9, 0xa0, 0xfc, 0xa6, 0x83, 0xd4, 0x99, 0x77, 0x55, 0xd3, 0x88, 0x63, 0xb2, 0xba, - 0x6a, 0x59, 0xd8, 0xd4, 0x37, 0x6f, 0xeb, 0x3b, 0xb0, 0x6d, 0xf8, 0x1e, 0x6e, 0x3b, 0x1f, 0x1c, - 0xec, 0xcb, 0xc1, 0x28, 0xcb, 0xd1, 0xb4, 0x5a, 0xe6, 0x7a, 0x98, 0x4b, 0x4c, 0x87, 0xb9, 0x1d, - 0xaf, 0x27, 0x73, 0x03, 0xa9, 0x11, 0x78, 0x55, 0x8e, 0x57, 0x73, 0xbe, 0x58, 0xca, 0x19, 0x13, - 0x44, 0xfa, 0xc7, 0x81, 0xbd, 0x40, 0x14, 0x9e, 0xac, 0x33, 0xad, 0x8d, 0xa0, 0xd3, 0x41, 0x1b, - 0x47, 0xbd, 0x00, 0xdb, 0xd4, 0xf7, 0xf0, 0xa3, 0xe6, 0x43, 0x51, 0xe7, 0xf6, 0x30, 0xcc, 0xbc, - 0x9b, 0x74, 0x7e, 0x5e, 0x6a, 0x04, 0x56, 0x95, 0xd7, 0xab, 0x49, 0xf7, 0x97, 0x92, 0x46, 0x85, - 0x90, 0x76, 0xc0, 0xc3, 0x53, 0xc3, 0x62, 0xfd, 0x06, 0xa2, 0x16, 0x31, 0x29, 0x3a, 0xf8, 0x96, - 0x04, 0xc9, 0x3a, 0xd5, 0xf9, 0x4b, 0x90, 0x89, 0xfb, 0xeb, 0xbc, 0x0c, 0x5d, 0x37, 0x7e, 0x5e, - 0x84, 0x6c, 0x48, 0xb6, 0xc4, 0xe0, 0xaf, 0xc0, 0xde, 0xfa, 0x29, 0x7a, 0x15, 0x45, 0x88, 0x11, - 0xaf, 0xe1, 0x7c, 0x00, 0xc2, 0x9a, 0xdf, 0xaf, 0x10, 0x05, 0x89, 0x52, 0xae, 0x21, 0x9c, 0x83, - 0x74, 0xe4, 0x23, 0x27, 0x2d, 0x7b, 0x47, 0x69, 0xe2, 0x5d, 0x85, 0x7b, 0x9f, 0x27, 0x83, 0x22, - 0x57, 0x7b, 0x7b, 0x3d, 0x12, 0xb9, 0x9b, 0x91, 0xc8, 0xfd, 0x1d, 0x89, 0xdc, 0x8f, 0xb1, 0x98, - 0xb8, 0x19, 0x8b, 0x89, 0x3f, 0x63, 0x31, 0x71, 0x59, 0xd2, 0x31, 0x6b, 0x3b, 0x2d, 0x59, 0x23, - 0x86, 0xc2, 0xc8, 0x47, 0x64, 0xe2, 0x4f, 0xa8, 0xd4, 0x53, 0x58, 0xaf, 0xa4, 0xb5, 0x55, 0x6c, - 0x2a, 0xdd, 0x63, 0xc5, 0x7b, 0x9e, 0x59, 0xdf, 0x42, 0xb4, 0x75, 0xdf, 0x7d, 0x95, 0x0f, 0x6f, - 0x03, 0x00, 0x00, 0xff, 0xff, 0x96, 0xa7, 0x0d, 0x6a, 0x31, 0x06, 0x00, 0x00, + // 685 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x4f, 0x4f, 0xdb, 0x3e, + 0x18, 0x6e, 0xe8, 0xef, 0x37, 0x51, 0x4f, 0x1b, 0x23, 0x43, 0x6a, 0x09, 0x90, 0x16, 0xef, 0x5f, + 0xc5, 0xd4, 0x46, 0xc0, 0x04, 0x52, 0x6f, 0x74, 0x20, 0x4e, 0xbd, 0x14, 0xd8, 0x01, 0x6d, 0xea, + 0xdc, 0xd8, 0xa4, 0xd6, 0x9a, 0x38, 0xaa, 0xdd, 0xaa, 0xdd, 0x69, 0xdb, 0x71, 0xa7, 0x7d, 0x14, + 0x0e, 0xfb, 0x10, 0x9c, 0x26, 0xb4, 0xd3, 0x4e, 0xd5, 0x04, 0xd3, 0x38, 0xec, 0xd6, 0x7d, 0x81, + 0xa9, 0x4d, 0x9a, 0xa6, 0xe4, 0xcf, 0xa1, 0x97, 0xc8, 0xce, 0xfb, 0xf8, 0x79, 0xde, 0xe7, 0xf5, + 0x6b, 0x1b, 0xc8, 0xa2, 0xab, 0xd9, 0x9c, 0x68, 0x9d, 0x4d, 0x4d, 0x74, 0x8b, 0x76, 0x8b, 0x09, + 0x26, 0xa7, 0x86, 0x23, 0x4e, 0x8a, 0x9d, 0x4d, 0x65, 0x11, 0x99, 0xd4, 0x62, 0xda, 0xe8, 0xeb, + 0x44, 0x95, 0x25, 0x83, 0x19, 0x6c, 0x34, 0xd4, 0x86, 0x23, 0xf7, 0xef, 0xb2, 0xce, 0xb8, 0xc9, + 0x78, 0xcd, 0x09, 0x38, 0x13, 0x37, 0x94, 0x76, 0x66, 0x9a, 0xc9, 0x8d, 0xa1, 0x8c, 0xc9, 0x0d, + 0x37, 0xb0, 0x3a, 0xd1, 0xc6, 0x94, 0x8b, 0x16, 0xad, 0xb7, 0x05, 0x65, 0x96, 0x13, 0x85, 0x1f, + 0x25, 0x90, 0xae, 0x70, 0x63, 0x9f, 0x72, 0x54, 0x6f, 0x92, 0x7d, 0x1f, 0x80, 0xcb, 0x3b, 0x20, + 0x85, 0xda, 0xa2, 0xc1, 0x5a, 0x54, 0xf4, 0x32, 0x52, 0x4e, 0xca, 0xa7, 0xca, 0x99, 0xef, 0x5f, + 0x0b, 0x4b, 0xae, 0xee, 0x1e, 0xc6, 0x2d, 0xc2, 0xf9, 0x91, 0x68, 0x51, 0xcb, 0xa8, 0x4e, 0xa0, + 0xa5, 0xe2, 0xa7, 0x9b, 0xf3, 0x8d, 0xc9, 0xfc, 0xf3, 0xcd, 0xf9, 0xc6, 0xca, 0x30, 0x83, 0x08, + 0x1d, 0xf8, 0x6d, 0x0e, 0x28, 0x15, 0x6e, 0x9c, 0xd8, 0x18, 0x09, 0x72, 0xd0, 0xd5, 0x9b, 0x6d, + 0x4c, 0xb0, 0xcb, 0x4e, 0x66, 0x4e, 0x43, 0x7e, 0x03, 0x1e, 0xa0, 0x31, 0x49, 0x4d, 0xb0, 0x1a, + 0xc2, 0x38, 0x33, 0x97, 0x4b, 0xe6, 0x53, 0xe5, 0xed, 0x41, 0x3f, 0x9b, 0xee, 0x21, 0xb3, 0x59, + 0x82, 0xb7, 0x11, 0x30, 0x92, 0xf9, 0xbe, 0x07, 0x3d, 0x66, 0x7b, 0x18, 0xcb, 0x67, 0xe0, 0xe1, + 0xd4, 0xe2, 0x16, 0x31, 0x59, 0x87, 0x64, 0x92, 0x23, 0x85, 0x9d, 0x41, 0x3f, 0xab, 0x84, 0x28, + 0x38, 0xa0, 0x68, 0x91, 0x45, 0x9f, 0x48, 0x75, 0x84, 0x2d, 0x6d, 0x06, 0xab, 0xa9, 0xba, 0xd5, + 0x8c, 0xa8, 0x18, 0xfc, 0x23, 0x81, 0x9c, 0x17, 0x7e, 0xd9, 0x24, 0x68, 0xc8, 0xbd, 0xa7, 0xeb, + 0xac, 0x6d, 0x89, 0x0a, 0xb2, 0x6d, 0x6a, 0x19, 0xb3, 0x97, 0xf5, 0x15, 0x98, 0x37, 0x5d, 0x8e, + 0x51, 0x39, 0xef, 0x6e, 0xad, 0x17, 0xbd, 0x56, 0x2e, 0x86, 0xab, 0x95, 0xd3, 0x17, 0xfd, 0x6c, + 0x62, 0xd0, 0xcf, 0x2e, 0x38, 0x35, 0x19, 0x13, 0xc0, 0xaa, 0xc7, 0x55, 0xda, 0x0d, 0xfa, 0x7c, + 0x3c, 0xe5, 0x33, 0xc2, 0x08, 0xfc, 0x25, 0x81, 0x35, 0x0f, 0xe4, 0xef, 0xac, 0x23, 0xbd, 0x41, + 0x70, 0xbb, 0x49, 0x66, 0xb6, 0x7a, 0x02, 0xe6, 0xb9, 0xcb, 0xe1, 0x5a, 0xcd, 0xf9, 0xac, 0x8e, + 0xe9, 0xb1, 0x5f, 0xf3, 0xb6, 0xd3, 0xf1, 0x7a, 0x58, 0xf5, 0xa8, 0x4a, 0x2f, 0x82, 0x4e, 0xd7, + 0xa7, 0x9c, 0x86, 0x99, 0x80, 0x7f, 0x25, 0xb0, 0xe2, 0x21, 0x2a, 0xd4, 0xf2, 0x83, 0x0e, 0x91, + 0x3d, 0xb3, 0xc9, 0x06, 0x58, 0x35, 0xa9, 0x55, 0xf3, 0xdf, 0x0d, 0x35, 0x03, 0xd9, 0x35, 0x4e, + 0x74, 0x66, 0xe1, 0xe1, 0x1e, 0x4b, 0xf9, 0xff, 0xca, 0xcf, 0x06, 0xfd, 0xec, 0x23, 0x77, 0xf3, + 0x62, 0xd0, 0xb0, 0xba, 0x6c, 0x06, 0x52, 0x3b, 0x72, 0x62, 0xa5, 0xad, 0xa0, 0xef, 0xec, 0x94, + 0xef, 0xa0, 0x2b, 0xb8, 0x00, 0xee, 0x1d, 0x98, 0xb6, 0xe8, 0x55, 0x09, 0xb7, 0x99, 0xc5, 0xc9, + 0xd6, 0xef, 0x24, 0x48, 0x56, 0xb8, 0x21, 0x9f, 0x82, 0x74, 0xd4, 0x85, 0xf1, 0xc4, 0xb7, 0x49, + 0xd1, 0xa7, 0x44, 0xc9, 0xf8, 0x60, 0x53, 0x1a, 0xf2, 0x19, 0x58, 0x8b, 0x3f, 0x3b, 0xcf, 0xc3, + 0x14, 0x22, 0xc0, 0x31, 0x3a, 0x6f, 0x81, 0x12, 0xd3, 0xb5, 0xf9, 0x30, 0x91, 0x30, 0x64, 0x8c, + 0xc2, 0x31, 0x58, 0x0a, 0xbd, 0xda, 0xe1, 0x34, 0x77, 0x18, 0x26, 0x86, 0xf5, 0x35, 0xc8, 0x44, + 0xb6, 0xe1, 0xd3, 0xb0, 0xac, 0x83, 0xb8, 0x68, 0x76, 0xe5, 0xff, 0x0f, 0x37, 0xe7, 0x1b, 0x52, + 0xf9, 0xf0, 0xe2, 0x4a, 0x95, 0x2e, 0xaf, 0x54, 0xe9, 0xe7, 0x95, 0x2a, 0x7d, 0xb9, 0x56, 0x13, + 0x97, 0xd7, 0x6a, 0xe2, 0xc7, 0xb5, 0x9a, 0x38, 0x2d, 0x18, 0x54, 0x34, 0xda, 0xf5, 0xa2, 0xce, + 0x4c, 0x4d, 0xb0, 0x77, 0xc4, 0xa2, 0xef, 0x49, 0xa1, 0xab, 0x89, 0x6e, 0x41, 0x6f, 0x20, 0x6a, + 0x69, 0x9d, 0x5d, 0xcd, 0x79, 0xf2, 0x44, 0xcf, 0x26, 0xbc, 0x7e, 0x67, 0xf4, 0xd2, 0x6d, 0xff, + 0x0b, 0x00, 0x00, 0xff, 0xff, 0xf4, 0x6e, 0x82, 0x52, 0x85, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -362,6 +425,8 @@ type MsgClient interface { UpdateDistributionSchedule(ctx context.Context, in *MsgUpdateDistributionSchedule, opts ...grpc.CallOption) (*EmptyResponse, error) // DisableDistributions is a governance operation to disable distributions. DisableDistributions(ctx context.Context, in *MsgDisableDistributions, opts ...grpc.CallOption) (*EmptyResponse, error) + // UpdateMinDistributionGap is a governance operation to update the minimum gap between distributions. + UpdateMinDistributionGap(ctx context.Context, in *MsgUpdateMinDistributionGap, opts ...grpc.CallOption) (*EmptyResponse, error) } type msgClient struct { @@ -408,6 +473,15 @@ func (c *msgClient) DisableDistributions(ctx context.Context, in *MsgDisableDist return out, nil } +func (c *msgClient) UpdateMinDistributionGap(ctx context.Context, in *MsgUpdateMinDistributionGap, opts ...grpc.CallOption) (*EmptyResponse, error) { + out := new(EmptyResponse) + err := c.cc.Invoke(ctx, "/tx.pse.v1.Msg/UpdateMinDistributionGap", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { // UpdateExcludedAddresses is a governance operation to update the list of excluded addresses. @@ -418,6 +492,8 @@ type MsgServer interface { UpdateDistributionSchedule(context.Context, *MsgUpdateDistributionSchedule) (*EmptyResponse, error) // DisableDistributions is a governance operation to disable distributions. DisableDistributions(context.Context, *MsgDisableDistributions) (*EmptyResponse, error) + // UpdateMinDistributionGap is a governance operation to update the minimum gap between distributions. + UpdateMinDistributionGap(context.Context, *MsgUpdateMinDistributionGap) (*EmptyResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -436,6 +512,9 @@ func (*UnimplementedMsgServer) UpdateDistributionSchedule(ctx context.Context, r func (*UnimplementedMsgServer) DisableDistributions(ctx context.Context, req *MsgDisableDistributions) (*EmptyResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method DisableDistributions not implemented") } +func (*UnimplementedMsgServer) UpdateMinDistributionGap(ctx context.Context, req *MsgUpdateMinDistributionGap) (*EmptyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateMinDistributionGap not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -513,6 +592,24 @@ func _Msg_DisableDistributions_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Msg_UpdateMinDistributionGap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateMinDistributionGap) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateMinDistributionGap(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tx.pse.v1.Msg/UpdateMinDistributionGap", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateMinDistributionGap(ctx, req.(*MsgUpdateMinDistributionGap)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "tx.pse.v1.Msg", HandlerType: (*MsgServer)(nil), @@ -533,6 +630,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "DisableDistributions", Handler: _Msg_DisableDistributions_Handler, }, + { + MethodName: "UpdateMinDistributionGap", + Handler: _Msg_UpdateMinDistributionGap_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "tx/pse/v1/tx.proto", @@ -704,6 +805,41 @@ func (m *MsgUpdateDistributionSchedule) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *MsgUpdateMinDistributionGap) 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 *MsgUpdateMinDistributionGap) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateMinDistributionGap) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.MinDistributionGapSeconds != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.MinDistributionGapSeconds)) + i-- + dAtA[i] = 0x10 + } + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *EmptyResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -814,6 +950,22 @@ func (m *MsgUpdateDistributionSchedule) Size() (n int) { return n } +func (m *MsgUpdateMinDistributionGap) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.MinDistributionGapSeconds != 0 { + n += 1 + sovTx(uint64(m.MinDistributionGapSeconds)) + } + return n +} + func (m *EmptyResponse) Size() (n int) { if m == nil { return 0 @@ -1289,6 +1441,107 @@ func (m *MsgUpdateDistributionSchedule) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgUpdateMinDistributionGap) 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: MsgUpdateMinDistributionGap: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateMinDistributionGap: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", 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.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MinDistributionGapSeconds", wireType) + } + m.MinDistributionGapSeconds = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MinDistributionGapSeconds |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 *EmptyResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 From e9143e212e233739f179c70216a60333bdb2e278 Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Mon, 23 Feb 2026 13:49:31 +0300 Subject: [PATCH 09/13] lint fix --- x/deterministicgas/spec/README.md | 1 + x/pse/keeper/distribution_test.go | 16 ++--- x/pse/keeper/genesis_test.go | 8 +-- x/pse/keeper/grpc_query_test.go | 24 +++---- x/pse/types/params_test.go | 106 +++++++++++++++--------------- 5 files changed, 78 insertions(+), 77 deletions(-) diff --git a/x/deterministicgas/spec/README.md b/x/deterministicgas/spec/README.md index d871d51b..a0ff98f0 100644 --- a/x/deterministicgas/spec/README.md +++ b/x/deterministicgas/spec/README.md @@ -306,6 +306,7 @@ and the formula for them is | `/tx.pse.v1.MsgUpdateClearingAccountMappings` | | `/tx.pse.v1.MsgUpdateDistributionSchedule` | | `/tx.pse.v1.MsgUpdateExcludedAddresses` | +| `/tx.pse.v1.MsgUpdateMinDistributionGap` | [//]: # (GENERATED DOC.) [//]: # (DO NOT EDIT MANUALLY!!!) diff --git a/x/pse/keeper/distribution_test.go b/x/pse/keeper/distribution_test.go index 2dfc98b3..c20a627e 100644 --- a/x/pse/keeper/distribution_test.go +++ b/x/pse/keeper/distribution_test.go @@ -63,8 +63,8 @@ func TestDistribution_GenesisRebuild(t *testing.T) { // Create and store allocation schedule with all clearing accounts schedule := []types.ScheduledDistribution{ { - Id: 1, - Timestamp: time1, + Id: 1, + Timestamp: time1, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(5000)}, {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, @@ -75,8 +75,8 @@ func TestDistribution_GenesisRebuild(t *testing.T) { }, }, { - Id: 2, - Timestamp: time2, + Id: 2, + Timestamp: time2, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(10000)}, {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(2000)}, @@ -185,8 +185,8 @@ func TestDistribution_PrecisionWithMultipleRecipients(t *testing.T) { startTime := uint64(time.Now().Add(-1 * time.Hour).Unix()) schedule := []types.ScheduledDistribution{ { - Id: 1, - Timestamp: startTime, + Id: 1, + Timestamp: startTime, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: allocationAmount}, {ClearingAccount: types.ClearingAccountAlliance, Amount: allocationAmount}, @@ -317,8 +317,8 @@ func TestDistribution_EndBlockFailure(t *testing.T) { startTime := uint64(time.Now().Add(-1 * time.Hour).Unix()) schedule := []types.ScheduledDistribution{ { - Id: 1, - Timestamp: startTime, + Id: 1, + Timestamp: startTime, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: allocationAmount}, {ClearingAccount: types.ClearingAccountAlliance, Amount: allocationAmount}, diff --git a/x/pse/keeper/genesis_test.go b/x/pse/keeper/genesis_test.go index 0459d09f..c6c9bd65 100644 --- a/x/pse/keeper/genesis_test.go +++ b/x/pse/keeper/genesis_test.go @@ -136,8 +136,8 @@ func TestGenesis_InvalidState(t *testing.T) { // Only include 4 accounts, missing Community and Team gs.ScheduledDistributions = []types.ScheduledDistribution{ { - Id: 1, - Timestamp: now, + Id: 1, + Timestamp: now, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, {ClearingAccount: types.ClearingAccountAlliance, Amount: sdkmath.NewInt(200)}, @@ -156,8 +156,8 @@ func TestGenesis_InvalidState(t *testing.T) { // Include only non-Community accounts, missing Community gs.ScheduledDistributions = []types.ScheduledDistribution{ { - Id: 1, - Timestamp: now, + Id: 1, + Timestamp: now, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, {ClearingAccount: types.ClearingAccountAlliance, Amount: sdkmath.NewInt(200)}, diff --git a/x/pse/keeper/grpc_query_test.go b/x/pse/keeper/grpc_query_test.go index 899df624..c7d059f1 100644 --- a/x/pse/keeper/grpc_query_test.go +++ b/x/pse/keeper/grpc_query_test.go @@ -285,15 +285,15 @@ func TestQueryAllocationSchedule(t *testing.T) { // Create schedule allocations at different future times schedule1 := types.ScheduledDistribution{ - Id: 1, - Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), + Id: 1, + Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(2000)}, }, } schedule2 := types.ScheduledDistribution{ - Id: 2, - Timestamp: uint64(currentTime.Add(2 * time.Hour).Unix()), + Id: 2, + Timestamp: uint64(currentTime.Add(2 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountTeam, Amount: sdkmath.NewInt(3000)}, }, @@ -317,8 +317,8 @@ func TestQueryAllocationSchedule(t *testing.T) { queryService := keeper.NewQueryService(testApp.PSEKeeper) schedule := types.ScheduledDistribution{ - Id: 1, - Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), + Id: 1, + Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(1000)}, {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(2000)}, @@ -344,22 +344,22 @@ func TestQueryAllocationSchedule(t *testing.T) { // Save schedule items in non-sequential order of id schedule3 := types.ScheduledDistribution{ - Id: 3, - Timestamp: uint64(currentTime.Add(3 * time.Hour).Unix()), + Id: 3, + Timestamp: uint64(currentTime.Add(3 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountAlliance, Amount: sdkmath.NewInt(3000)}, }, } schedule1 := types.ScheduledDistribution{ - Id: 1, - Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), + Id: 1, + Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountPartnership, Amount: sdkmath.NewInt(1000)}, }, } schedule2 := types.ScheduledDistribution{ - Id: 2, - Timestamp: uint64(currentTime.Add(2 * time.Hour).Unix()), + Id: 2, + Timestamp: uint64(currentTime.Add(2 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountInvestors, Amount: sdkmath.NewInt(2000)}, }, diff --git a/x/pse/types/params_test.go b/x/pse/types/params_test.go index 8ccff664..16d32788 100644 --- a/x/pse/types/params_test.go +++ b/x/pse/types/params_test.go @@ -313,9 +313,9 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "valid_single_period", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), - Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), + Id: 1, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, }, expectErr: false, @@ -324,14 +324,14 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "valid_multiple_periods_sorted", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), - Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), + Id: 1, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, { - Id: 2, - Timestamp: getTestTimestamp(12), - Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), + Id: 2, + Timestamp: getTestTimestamp(12), + Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, }, expectErr: false, @@ -340,8 +340,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "valid_with_community_account", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), + Id: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ // All clearing accounts (including Community) should be in schedule {ClearingAccount: ClearingAccountCommunity, Amount: sdkmath.NewInt(5000)}, @@ -359,9 +359,9 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_zero_id", schedule: []ScheduledDistribution{ { - Id: 0, - Timestamp: getTestTimestamp(0), - Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), + Id: 0, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, }, expectErr: true, @@ -371,14 +371,14 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_non_sequential_id", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), - Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), + Id: 1, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, { - Id: 5, - Timestamp: getTestTimestamp(12), - Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), + Id: 5, + Timestamp: getTestTimestamp(12), + Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, }, expectErr: true, @@ -388,8 +388,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_zero_timestamp", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: 0, + Id: 1, + Timestamp: 0, Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, }, @@ -402,14 +402,14 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_duplicate_timestamp", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), - Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), + Id: 1, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, { - Id: 2, - Timestamp: getTestTimestamp(0), - Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), + Id: 2, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, }, expectErr: true, @@ -419,14 +419,14 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_unsorted_schedule", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(12), - Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), + Id: 1, + Timestamp: getTestTimestamp(12), + Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, { - Id: 2, - Timestamp: getTestTimestamp(0), - Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), + Id: 2, + Timestamp: getTestTimestamp(0), + Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, }, expectErr: true, @@ -436,9 +436,9 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_empty_allocations_array", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), - Allocations: []ClearingAccountAllocation{}, + Id: 1, + Timestamp: getTestTimestamp(0), + Allocations: []ClearingAccountAllocation{}, }, }, expectErr: true, @@ -448,8 +448,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_too_few_allocations", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), + Id: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, }, @@ -462,8 +462,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_empty_clearing_account", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), + Id: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: "", Amount: sdkmath.NewInt(1000)}, {ClearingAccount: ClearingAccountAlliance, Amount: sdkmath.NewInt(1000)}, @@ -480,8 +480,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_unknown_clearing_account", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), + Id: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: "unknown_module", Amount: sdkmath.NewInt(1000)}, {ClearingAccount: ClearingAccountCommunity, Amount: sdkmath.NewInt(1000)}, @@ -500,8 +500,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_duplicate_clearing_account_in_period", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), + Id: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(2000)}, // Duplicate @@ -519,8 +519,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_missing_clearing_account", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), + Id: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, {ClearingAccount: ClearingAccountAlliance, Amount: sdkmath.NewInt(1000)}, @@ -537,8 +537,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_nil_amount", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), + Id: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.Int{}}, {ClearingAccount: ClearingAccountAlliance, Amount: sdkmath.NewInt(1000)}, @@ -555,8 +555,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_negative_amount", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), + Id: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(-1000)}, {ClearingAccount: ClearingAccountAlliance, Amount: sdkmath.NewInt(1000)}, @@ -573,8 +573,8 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_zero_amount", schedule: []ScheduledDistribution{ { - Id: 1, - Timestamp: getTestTimestamp(0), + Id: 1, + Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.ZeroInt()}, {ClearingAccount: ClearingAccountAlliance, Amount: sdkmath.NewInt(1000)}, From 749a69bdf1ad5f06e8c5641d3413d6c9465cd8bd Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Mon, 23 Feb 2026 14:20:19 +0300 Subject: [PATCH 10/13] fix integration test ci --- integration-tests/modules/pse_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/integration-tests/modules/pse_test.go b/integration-tests/modules/pse_test.go index 7e4061af..2069ed24 100644 --- a/integration-tests/modules/pse_test.go +++ b/integration-tests/modules/pse_test.go @@ -210,6 +210,10 @@ func TestPSEDistribution(t *testing.T) { chain.Governance.ExpeditedProposalFromMsgAndVote( ctx, t, nil, "-", "-", "-", govtypesv1.OptionYes, + &psetypes.MsgUpdateMinDistributionGap{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + MinDistributionGapSeconds: 0, + }, &psetypes.MsgUpdateDistributionSchedule{ Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), Schedule: []psetypes.ScheduledDistribution{ From cc013116d4a97419d366481665fe378627827322 Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Mon, 23 Feb 2026 14:41:53 +0300 Subject: [PATCH 11/13] fix ci test --- x/deterministicgas/config_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/deterministicgas/config_test.go b/x/deterministicgas/config_test.go index 78b4d18b..80083ea9 100644 --- a/x/deterministicgas/config_test.go +++ b/x/deterministicgas/config_test.go @@ -97,10 +97,10 @@ func TestDeterministicGas_DeterministicMessages(t *testing.T) { // To make sure we do not increase/decrease deterministic and extension types accidentally, // we assert length to be equal to exact number, so each change requires // explicit adjustment of tests. - assert.Equal(t, 94, nondeterministicMsgCount) + assert.Equal(t, 95, nondeterministicMsgCount) assert.Equal(t, 68, deterministicMsgCount) assert.Equal(t, 12, extensionMsgCount) - assert.Equal(t, 150, nonExtensionMsgCount) + assert.Equal(t, 151, nonExtensionMsgCount) } func TestDeterministicGas_GasRequiredByMessage(t *testing.T) { From f486949080553f5e9c3fec021247fffd24f5a77a Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Mon, 23 Feb 2026 15:39:53 +0300 Subject: [PATCH 12/13] fix Id field name as ID --- integration-tests/modules/pse_test.go | 6 +-- proto/tx/pse/v1/distribution.proto | 1 + x/pse/keeper/distribution.go | 6 +-- x/pse/keeper/distribution_test.go | 10 ++-- x/pse/keeper/genesis.go | 2 +- x/pse/keeper/genesis_test.go | 4 +- x/pse/keeper/grpc_query_test.go | 12 ++--- x/pse/keeper/msg_server_test.go | 8 +-- x/pse/types/distribution.pb.go | 78 +++++++++++++-------------- x/pse/types/params.go | 6 +-- x/pse/types/params_test.go | 42 +++++++-------- 11 files changed, 88 insertions(+), 87 deletions(-) diff --git a/integration-tests/modules/pse_test.go b/integration-tests/modules/pse_test.go index 2069ed24..16c7e127 100644 --- a/integration-tests/modules/pse_test.go +++ b/integration-tests/modules/pse_test.go @@ -217,9 +217,9 @@ func TestPSEDistribution(t *testing.T) { &psetypes.MsgUpdateDistributionSchedule{ Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), Schedule: []psetypes.ScheduledDistribution{ - {Id: 1, Timestamp: uint64(distributionStartTime.Add(30 * time.Second).Unix()), Allocations: allocations}, - {Id: 2, Timestamp: uint64(distributionStartTime.Add(60 * time.Second).Unix()), Allocations: allocations}, - {Id: 3, Timestamp: uint64(distributionStartTime.Add(90 * time.Second).Unix()), Allocations: allocations}, + {ID: 1, Timestamp: uint64(distributionStartTime.Add(30 * time.Second).Unix()), Allocations: allocations}, + {ID: 2, Timestamp: uint64(distributionStartTime.Add(60 * time.Second).Unix()), Allocations: allocations}, + {ID: 3, Timestamp: uint64(distributionStartTime.Add(90 * time.Second).Unix()), Allocations: allocations}, }, }, &psetypes.MsgUpdateClearingAccountMappings{ diff --git a/proto/tx/pse/v1/distribution.proto b/proto/tx/pse/v1/distribution.proto index 12e4d96b..1891f271 100644 --- a/proto/tx/pse/v1/distribution.proto +++ b/proto/tx/pse/v1/distribution.proto @@ -59,6 +59,7 @@ message ScheduledDistribution { // id is the unique, sequential identifier for this distribution. // Used as the storage key in the AllocationSchedule map. uint64 id = 3 [ + (gogoproto.customname) = "ID", (gogoproto.moretags) = "yaml:\"id\"" ]; } diff --git a/x/pse/keeper/distribution.go b/x/pse/keeper/distribution.go index 9124922e..1bad66b9 100644 --- a/x/pse/keeper/distribution.go +++ b/x/pse/keeper/distribution.go @@ -50,7 +50,7 @@ func (k Keeper) ProcessNextDistribution(ctx context.Context) error { } // Remove the completed distribution from the schedule - if err := k.AllocationSchedule.Remove(ctx, scheduledDistribution.Id); err != nil { + if err := k.AllocationSchedule.Remove(ctx, scheduledDistribution.ID); err != nil { return err } @@ -220,8 +220,8 @@ func (k Keeper) distributeAllocatedTokens( // Each scheduled distribution is stored in the AllocationSchedule map, indexed by its ID. func (k Keeper) SaveDistributionSchedule(ctx context.Context, schedule []types.ScheduledDistribution) error { for _, scheduledDist := range schedule { - if err := k.AllocationSchedule.Set(ctx, scheduledDist.Id, scheduledDist); err != nil { - return errorsmod.Wrapf(err, "failed to save distribution with id %d", scheduledDist.Id) + if err := k.AllocationSchedule.Set(ctx, scheduledDist.ID, scheduledDist); err != nil { + return errorsmod.Wrapf(err, "failed to save distribution with id %d", scheduledDist.ID) } } return nil diff --git a/x/pse/keeper/distribution_test.go b/x/pse/keeper/distribution_test.go index c20a627e..fa386454 100644 --- a/x/pse/keeper/distribution_test.go +++ b/x/pse/keeper/distribution_test.go @@ -63,7 +63,7 @@ func TestDistribution_GenesisRebuild(t *testing.T) { // Create and store allocation schedule with all clearing accounts schedule := []types.ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: time1, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(5000)}, @@ -75,7 +75,7 @@ func TestDistribution_GenesisRebuild(t *testing.T) { }, }, { - Id: 2, + ID: 2, Timestamp: time2, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(10000)}, @@ -90,7 +90,7 @@ func TestDistribution_GenesisRebuild(t *testing.T) { // Store in allocation schedule map for _, scheduledDist := range schedule { - err = pseKeeper.AllocationSchedule.Set(ctx, scheduledDist.Id, scheduledDist) + err = pseKeeper.AllocationSchedule.Set(ctx, scheduledDist.ID, scheduledDist) requireT.NoError(err) } @@ -185,7 +185,7 @@ func TestDistribution_PrecisionWithMultipleRecipients(t *testing.T) { startTime := uint64(time.Now().Add(-1 * time.Hour).Unix()) schedule := []types.ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: startTime, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: allocationAmount}, @@ -317,7 +317,7 @@ func TestDistribution_EndBlockFailure(t *testing.T) { startTime := uint64(time.Now().Add(-1 * time.Hour).Unix()) schedule := []types.ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: startTime, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: allocationAmount}, diff --git a/x/pse/keeper/genesis.go b/x/pse/keeper/genesis.go index b8acbbf9..7e479440 100644 --- a/x/pse/keeper/genesis.go +++ b/x/pse/keeper/genesis.go @@ -23,7 +23,7 @@ func (k Keeper) InitGenesis(ctx context.Context, genState types.GenesisState) er // Populate allocation schedule from genesis state for _, scheduledDist := range genState.ScheduledDistributions { - if err := k.AllocationSchedule.Set(ctx, scheduledDist.Id, scheduledDist); err != nil { + if err := k.AllocationSchedule.Set(ctx, scheduledDist.ID, scheduledDist); err != nil { return err } } diff --git a/x/pse/keeper/genesis_test.go b/x/pse/keeper/genesis_test.go index c6c9bd65..287a54c8 100644 --- a/x/pse/keeper/genesis_test.go +++ b/x/pse/keeper/genesis_test.go @@ -136,7 +136,7 @@ func TestGenesis_InvalidState(t *testing.T) { // Only include 4 accounts, missing Community and Team gs.ScheduledDistributions = []types.ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: now, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, @@ -156,7 +156,7 @@ func TestGenesis_InvalidState(t *testing.T) { // Include only non-Community accounts, missing Community gs.ScheduledDistributions = []types.ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: now, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, diff --git a/x/pse/keeper/grpc_query_test.go b/x/pse/keeper/grpc_query_test.go index c7d059f1..01ae681d 100644 --- a/x/pse/keeper/grpc_query_test.go +++ b/x/pse/keeper/grpc_query_test.go @@ -285,14 +285,14 @@ func TestQueryAllocationSchedule(t *testing.T) { // Create schedule allocations at different future times schedule1 := types.ScheduledDistribution{ - Id: 1, + ID: 1, Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountFoundation, Amount: sdkmath.NewInt(2000)}, }, } schedule2 := types.ScheduledDistribution{ - Id: 2, + ID: 2, Timestamp: uint64(currentTime.Add(2 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountTeam, Amount: sdkmath.NewInt(3000)}, @@ -317,7 +317,7 @@ func TestQueryAllocationSchedule(t *testing.T) { queryService := keeper.NewQueryService(testApp.PSEKeeper) schedule := types.ScheduledDistribution{ - Id: 1, + ID: 1, Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(1000)}, @@ -344,21 +344,21 @@ func TestQueryAllocationSchedule(t *testing.T) { // Save schedule items in non-sequential order of id schedule3 := types.ScheduledDistribution{ - Id: 3, + ID: 3, Timestamp: uint64(currentTime.Add(3 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountAlliance, Amount: sdkmath.NewInt(3000)}, }, } schedule1 := types.ScheduledDistribution{ - Id: 1, + ID: 1, Timestamp: uint64(currentTime.Add(1 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountPartnership, Amount: sdkmath.NewInt(1000)}, }, } schedule2 := types.ScheduledDistribution{ - Id: 2, + ID: 2, Timestamp: uint64(currentTime.Add(2 * time.Hour).Unix()), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountInvestors, Amount: sdkmath.NewInt(2000)}, diff --git a/x/pse/keeper/msg_server_test.go b/x/pse/keeper/msg_server_test.go index 1d42e114..6915a54b 100644 --- a/x/pse/keeper/msg_server_test.go +++ b/x/pse/keeper/msg_server_test.go @@ -182,7 +182,7 @@ func TestMsgUpdateAllocationSchedule(t *testing.T) { baseTimestamp := uint64(1700000000) // Some future timestamp for i := range numPeriods { schedule[i] = types.ScheduledDistribution{ - Id: uint64(i + 1), + ID: uint64(i + 1), Timestamp: baseTimestamp + uint64(i*86400), // One day apart Allocations: createAllAllocations(amount), } @@ -226,7 +226,7 @@ func TestMsgUpdateAllocationSchedule(t *testing.T) { Authority: authority, Schedule: []types.ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: uint64(1700000000), Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(1000000)}, @@ -315,7 +315,7 @@ func TestMsgUpdateMinDistributionGap(t *testing.T) { daySeconds := uint64(86400) schedule := []types.ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: baseTimestamp, Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(1000)}, @@ -327,7 +327,7 @@ func TestMsgUpdateMinDistributionGap(t *testing.T) { }, }, { - Id: 2, + ID: 2, Timestamp: baseTimestamp + daySeconds, // 1 day later Allocations: []types.ClearingAccountAllocation{ {ClearingAccount: types.ClearingAccountCommunity, Amount: sdkmath.NewInt(1000)}, diff --git a/x/pse/types/distribution.pb.go b/x/pse/types/distribution.pb.go index 271d33a9..4010e758 100644 --- a/x/pse/types/distribution.pb.go +++ b/x/pse/types/distribution.pb.go @@ -143,7 +143,7 @@ type ScheduledDistribution struct { Allocations []ClearingAccountAllocation `protobuf:"bytes,2,rep,name=allocations,proto3" json:"allocations" yaml:"allocations"` // id is the unique, sequential identifier for this distribution. // Used as the storage key in the AllocationSchedule map. - Id uint64 `protobuf:"varint,3,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` + ID uint64 `protobuf:"varint,3,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` } func (m *ScheduledDistribution) Reset() { *m = ScheduledDistribution{} } @@ -193,9 +193,9 @@ func (m *ScheduledDistribution) GetAllocations() []ClearingAccountAllocation { return nil } -func (m *ScheduledDistribution) GetId() uint64 { +func (m *ScheduledDistribution) GetID() uint64 { if m != nil { - return m.Id + return m.ID } return 0 } @@ -209,36 +209,36 @@ func init() { func init() { proto.RegisterFile("tx/pse/v1/distribution.proto", fileDescriptor_a549fe743b42ab69) } var fileDescriptor_a549fe743b42ab69 = []byte{ - // 459 bytes of a gzipped FileDescriptorProto + // 464 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0xcf, 0x6a, 0xd4, 0x40, - 0x18, 0xdf, 0x6c, 0xa5, 0x90, 0x29, 0xc5, 0x12, 0xb7, 0xba, 0x5d, 0x35, 0x29, 0xc1, 0x43, 0x2f, - 0x9b, 0xa1, 0x15, 0x14, 0xc4, 0xcb, 0x46, 0x51, 0x7a, 0xf0, 0x92, 0x7a, 0xf2, 0xb2, 0xcc, 0xce, - 0x0c, 0xd9, 0xa1, 0xc9, 0x4c, 0xc8, 0x7c, 0xbb, 0x6c, 0x7d, 0x0a, 0x1f, 0xc6, 0x8b, 0x6f, 0x50, - 0x2f, 0x52, 0x3c, 0x89, 0x87, 0x41, 0x76, 0xdf, 0x20, 0x4f, 0x20, 0xc9, 0x84, 0xb4, 0x16, 0xbd, - 0x79, 0x4b, 0xbe, 0xdf, 0x1f, 0x7e, 0xbf, 0x6f, 0x3e, 0xf4, 0x08, 0x56, 0xb8, 0xd0, 0x1c, 0x2f, - 0x8f, 0x31, 0x13, 0x1a, 0x4a, 0x31, 0x5b, 0x80, 0x50, 0x32, 0x2a, 0x4a, 0x05, 0xca, 0x73, 0x61, - 0x15, 0x15, 0x9a, 0x47, 0xcb, 0xe3, 0xd1, 0x20, 0x55, 0xa9, 0x6a, 0xa6, 0xb8, 0xfe, 0xb2, 0x84, - 0xd1, 0x01, 0x55, 0x3a, 0x57, 0x7a, 0x6a, 0x01, 0xfb, 0x63, 0xa1, 0xf0, 0xab, 0x83, 0xee, 0xbf, - 0xca, 0x38, 0x29, 0x85, 0x4c, 0x27, 0x94, 0xaa, 0x85, 0x84, 0x77, 0xa4, 0x28, 0x84, 0x4c, 0xbd, - 0x37, 0x68, 0x8f, 0xb6, 0xc8, 0x94, 0x58, 0x68, 0xe8, 0x1c, 0x3a, 0x47, 0x6e, 0xfc, 0xb0, 0x32, - 0xc1, 0x83, 0x0b, 0x92, 0x67, 0x2f, 0xc2, 0xdb, 0x8c, 0x30, 0xb9, 0x4b, 0xff, 0xb4, 0xf3, 0x52, - 0x74, 0xaf, 0xe4, 0x54, 0x14, 0x82, 0x4b, 0x98, 0x12, 0xc6, 0x4a, 0xae, 0x35, 0xd7, 0xc3, 0xfe, - 0xe1, 0xd6, 0x91, 0x1b, 0x3f, 0xab, 0x4c, 0x30, 0xb2, 0x56, 0x7f, 0x21, 0x85, 0xdf, 0x3f, 0x8f, - 0x07, 0x6d, 0xde, 0x89, 0x1d, 0x9e, 0x41, 0xed, 0x9d, 0x78, 0x1d, 0x7b, 0xd2, 0x91, 0xbf, 0x38, - 0xe8, 0xe0, 0x56, 0x97, 0x49, 0x96, 0x29, 0x4a, 0xea, 0x5d, 0xfd, 0xb7, 0x3a, 0xef, 0xd1, 0x36, - 0xc9, 0x1b, 0x75, 0xbf, 0x51, 0xbf, 0xbc, 0x34, 0x41, 0xef, 0xa7, 0x09, 0xf6, 0x6d, 0x4e, 0xcd, - 0xce, 0x23, 0xa1, 0x70, 0x4e, 0x60, 0x1e, 0x9d, 0x4a, 0xa8, 0x4c, 0xb0, 0x6b, 0xad, 0xad, 0xa8, - 0x6e, 0x84, 0xda, 0x46, 0xa7, 0x12, 0x92, 0xd6, 0x2b, 0xfc, 0xe6, 0xa0, 0xfd, 0x33, 0x3a, 0xe7, - 0x6c, 0x91, 0x71, 0xf6, 0xfa, 0xc6, 0x1b, 0x7b, 0x27, 0xc8, 0x05, 0x91, 0x73, 0x0d, 0x24, 0x2f, - 0x9a, 0xc0, 0x77, 0xe2, 0x41, 0x65, 0x82, 0x3d, 0xeb, 0xda, 0x41, 0x61, 0x72, 0x4d, 0xf3, 0x66, - 0x68, 0x87, 0x74, 0xcd, 0xed, 0xaa, 0x77, 0x4e, 0x9e, 0x44, 0xdd, 0x9d, 0x44, 0xff, 0x5c, 0x53, - 0x3c, 0xaa, 0xeb, 0x54, 0x26, 0xf0, 0xda, 0xd4, 0xd7, 0x36, 0x61, 0x72, 0xd3, 0xd4, 0x7b, 0x8c, - 0xfa, 0x82, 0x0d, 0xb7, 0x9a, 0x40, 0xbb, 0x95, 0x09, 0x5c, 0x2b, 0x10, 0x2c, 0x4c, 0xfa, 0x82, - 0xc5, 0x6f, 0x2f, 0xd7, 0xbe, 0x73, 0xb5, 0xf6, 0x9d, 0x5f, 0x6b, 0xdf, 0xf9, 0xb4, 0xf1, 0x7b, - 0x57, 0x1b, 0xbf, 0xf7, 0x63, 0xe3, 0xf7, 0x3e, 0x8c, 0x53, 0x01, 0xf3, 0xc5, 0x2c, 0xa2, 0x2a, - 0xc7, 0xa0, 0xce, 0xb9, 0x14, 0x1f, 0xf9, 0x78, 0x85, 0x61, 0x35, 0xa6, 0x73, 0x22, 0x24, 0x5e, - 0x3e, 0xc7, 0xf6, 0xda, 0xe1, 0xa2, 0xe0, 0x7a, 0xb6, 0xdd, 0x1c, 0xea, 0xd3, 0xdf, 0x01, 0x00, - 0x00, 0xff, 0xff, 0xaf, 0x42, 0x2e, 0x00, 0x04, 0x03, 0x00, 0x00, + 0x18, 0xdf, 0xa4, 0x52, 0xc8, 0x14, 0xb1, 0xa4, 0x5b, 0xdd, 0xae, 0x92, 0x29, 0xd1, 0x43, 0x2f, + 0x9b, 0xa1, 0x15, 0x14, 0xc4, 0xcb, 0xc6, 0xa2, 0xec, 0xc1, 0x4b, 0xea, 0xc9, 0xcb, 0x32, 0x3b, + 0x33, 0x64, 0x87, 0x26, 0x33, 0x21, 0x33, 0xbb, 0x6c, 0x7d, 0x0a, 0x1f, 0xc6, 0x8b, 0x6f, 0x50, + 0x6f, 0x45, 0x3c, 0x88, 0x87, 0x41, 0x76, 0xdf, 0x20, 0x4f, 0x20, 0xc9, 0x84, 0xb4, 0x16, 0xbd, + 0xf5, 0x96, 0x7c, 0xbf, 0x3f, 0xfc, 0x7e, 0xdf, 0x7c, 0xe0, 0x89, 0x5e, 0xa1, 0x42, 0x31, 0xb4, + 0x3c, 0x46, 0x94, 0x2b, 0x5d, 0xf2, 0xd9, 0x42, 0x73, 0x29, 0xa2, 0xa2, 0x94, 0x5a, 0xfa, 0x9e, + 0x5e, 0x45, 0x85, 0x62, 0xd1, 0xf2, 0x78, 0xd8, 0x4f, 0x65, 0x2a, 0x9b, 0x29, 0xaa, 0xbf, 0x2c, + 0x61, 0x78, 0x40, 0xa4, 0xca, 0xa5, 0x9a, 0x5a, 0xc0, 0xfe, 0x58, 0x28, 0xfc, 0xe6, 0x80, 0x87, + 0x6f, 0x32, 0x86, 0x4b, 0x2e, 0xd2, 0x31, 0x21, 0x72, 0x21, 0xf4, 0x7b, 0x5c, 0x14, 0x5c, 0xa4, + 0xfe, 0x5b, 0xb0, 0x4b, 0x5a, 0x64, 0x8a, 0x2d, 0x34, 0x70, 0x0e, 0x9d, 0x23, 0x2f, 0x7e, 0x5c, + 0x19, 0xf8, 0xe8, 0x02, 0xe7, 0xd9, 0xab, 0xf0, 0x36, 0x23, 0x4c, 0x1e, 0x90, 0xbf, 0xed, 0xfc, + 0x14, 0xec, 0x95, 0x8c, 0xf0, 0x82, 0x33, 0xa1, 0xa7, 0x98, 0xd2, 0x92, 0x29, 0xc5, 0xd4, 0xc0, + 0x3d, 0xdc, 0x3a, 0xf2, 0xe2, 0x17, 0x95, 0x81, 0x43, 0x6b, 0xf5, 0x0f, 0x52, 0xf8, 0xfd, 0xcb, + 0xa8, 0xdf, 0xe6, 0x1d, 0xdb, 0xe1, 0x99, 0xae, 0xbd, 0x13, 0xbf, 0x63, 0x8f, 0x3b, 0xf2, 0x57, + 0x07, 0x1c, 0xdc, 0xea, 0x32, 0xce, 0x32, 0x49, 0x70, 0xbd, 0xab, 0x3b, 0xab, 0xf3, 0x01, 0x6c, + 0xe3, 0xbc, 0x51, 0xbb, 0x8d, 0xfa, 0xf5, 0xa5, 0x81, 0xbd, 0x5f, 0x06, 0xee, 0xdb, 0x9c, 0x8a, + 0x9e, 0x47, 0x5c, 0xa2, 0x1c, 0xeb, 0x79, 0x34, 0x11, 0xba, 0x32, 0xf0, 0xbe, 0xb5, 0xb6, 0xa2, + 0xba, 0x11, 0x68, 0x1b, 0x4d, 0x84, 0x4e, 0x5a, 0xaf, 0xf0, 0x87, 0x03, 0xf6, 0xcf, 0xc8, 0x9c, + 0xd1, 0x45, 0xc6, 0xe8, 0xe9, 0x8d, 0x37, 0xf6, 0x4f, 0x80, 0xa7, 0x79, 0xce, 0x94, 0xc6, 0x79, + 0xd1, 0x04, 0xbe, 0x17, 0xf7, 0x2b, 0x03, 0x77, 0xad, 0x6b, 0x07, 0x85, 0xc9, 0x35, 0xcd, 0x9f, + 0x81, 0x1d, 0xdc, 0x35, 0xb7, 0xab, 0xde, 0x39, 0x79, 0x16, 0x75, 0x77, 0x12, 0xfd, 0x77, 0x4d, + 0xf1, 0xb0, 0xae, 0x53, 0x19, 0xe8, 0xb7, 0xa9, 0xaf, 0x6d, 0xc2, 0xe4, 0xa6, 0xa9, 0xff, 0x14, + 0xb8, 0x9c, 0x0e, 0xb6, 0x9a, 0x40, 0x7b, 0x6b, 0x03, 0xdd, 0xc9, 0x69, 0x65, 0xa0, 0x67, 0x65, + 0x9c, 0x86, 0x89, 0xcb, 0x69, 0xfc, 0xee, 0x72, 0x1d, 0x38, 0x57, 0xeb, 0xc0, 0xf9, 0xbd, 0x0e, + 0x9c, 0xcf, 0x9b, 0xa0, 0x77, 0xb5, 0x09, 0x7a, 0x3f, 0x37, 0x41, 0xef, 0xe3, 0x28, 0xe5, 0x7a, + 0xbe, 0x98, 0x45, 0x44, 0xe6, 0x48, 0xcb, 0x73, 0x26, 0xf8, 0x27, 0x36, 0x5a, 0x21, 0xbd, 0x1a, + 0x91, 0x39, 0xe6, 0x02, 0x2d, 0x5f, 0x22, 0x7b, 0xf3, 0xfa, 0xa2, 0x60, 0x6a, 0xb6, 0xdd, 0x9c, + 0xeb, 0xf3, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xe3, 0xf0, 0x10, 0x7e, 0x0a, 0x03, 0x00, 0x00, } func (m *ClearingAccountMapping) Marshal() (dAtA []byte, err error) { @@ -340,8 +340,8 @@ func (m *ScheduledDistribution) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Id != 0 { - i = encodeVarintDistribution(dAtA, i, uint64(m.Id)) + if m.ID != 0 { + i = encodeVarintDistribution(dAtA, i, uint64(m.ID)) i-- dAtA[i] = 0x18 } @@ -427,8 +427,8 @@ func (m *ScheduledDistribution) Size() (n int) { n += 1 + l + sovDistribution(uint64(l)) } } - if m.Id != 0 { - n += 1 + sovDistribution(uint64(m.Id)) + if m.ID != 0 { + n += 1 + sovDistribution(uint64(m.ID)) } return n } @@ -753,9 +753,9 @@ func (m *ScheduledDistribution) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 3: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) } - m.Id = 0 + m.ID = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowDistribution @@ -765,7 +765,7 @@ func (m *ScheduledDistribution) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Id |= uint64(b&0x7F) << shift + m.ID |= uint64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/pse/types/params.go b/x/pse/types/params.go index 657818f8..98398ebb 100644 --- a/x/pse/types/params.go +++ b/x/pse/types/params.go @@ -134,15 +134,15 @@ func ValidateDistributionSchedule(schedule []ScheduledDistribution) error { for i, period := range schedule { // Validate id is non-zero - if period.Id == 0 { + if period.ID == 0 { return errorsmod.Wrapf(ErrInvalidParam, "period %d: id cannot be zero", i) } // Validate id is strictly increasing and sequential (each ID = previous + 1). - if i > 0 && period.Id != schedule[i-1].Id+1 { + if i > 0 && period.ID != schedule[i-1].ID+1 { return errorsmod.Wrapf(ErrInvalidParam, "period %d: id must be sequential, expected %d but got %d", - i, schedule[i-1].Id+1, period.Id) + i, schedule[i-1].ID+1, period.ID) } // Validate timestamp is not zero diff --git a/x/pse/types/params_test.go b/x/pse/types/params_test.go index 16d32788..702d4f16 100644 --- a/x/pse/types/params_test.go +++ b/x/pse/types/params_test.go @@ -313,7 +313,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "valid_single_period", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, @@ -324,12 +324,12 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "valid_multiple_periods_sorted", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, { - Id: 2, + ID: 2, Timestamp: getTestTimestamp(12), Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, @@ -340,7 +340,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "valid_with_community_account", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ // All clearing accounts (including Community) should be in schedule @@ -359,7 +359,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_zero_id", schedule: []ScheduledDistribution{ { - Id: 0, + ID: 0, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, @@ -371,12 +371,12 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_non_sequential_id", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, { - Id: 5, + ID: 5, Timestamp: getTestTimestamp(12), Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, @@ -388,7 +388,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_zero_timestamp", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: 0, Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, @@ -402,12 +402,12 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_duplicate_timestamp", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, { - Id: 2, + ID: 2, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, @@ -419,12 +419,12 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_unsorted_schedule", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(12), Allocations: createAllModuleAllocations(sdkmath.NewInt(2000)), }, { - Id: 2, + ID: 2, Timestamp: getTestTimestamp(0), Allocations: createAllModuleAllocations(sdkmath.NewInt(1000)), }, @@ -436,7 +436,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_empty_allocations_array", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{}, }, @@ -448,7 +448,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_too_few_allocations", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, @@ -462,7 +462,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_empty_clearing_account", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: "", Amount: sdkmath.NewInt(1000)}, @@ -480,7 +480,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_unknown_clearing_account", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: "unknown_module", Amount: sdkmath.NewInt(1000)}, @@ -500,7 +500,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_duplicate_clearing_account_in_period", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, @@ -519,7 +519,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_missing_clearing_account", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(1000)}, @@ -537,7 +537,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_nil_amount", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.Int{}}, @@ -555,7 +555,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_negative_amount", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.NewInt(-1000)}, @@ -573,7 +573,7 @@ func TestValidateAllocationSchedule(t *testing.T) { name: "invalid_zero_amount", schedule: []ScheduledDistribution{ { - Id: 1, + ID: 1, Timestamp: getTestTimestamp(0), Allocations: []ClearingAccountAllocation{ {ClearingAccount: ClearingAccountFoundation, Amount: sdkmath.ZeroInt()}, From cfe8dd15bf0b701f8e70cde6d1186e1c098fed82 Mon Sep 17 00:00:00 2001 From: metalarm10 Date: Mon, 23 Feb 2026 15:48:20 +0300 Subject: [PATCH 13/13] merge timestamp and ID ordering checks in schedule validation --- x/pse/types/params.go | 32 ++++++++++++-------------------- x/pse/types/params_test.go | 4 ++-- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/x/pse/types/params.go b/x/pse/types/params.go index 98398ebb..f6663824 100644 --- a/x/pse/types/params.go +++ b/x/pse/types/params.go @@ -129,38 +129,30 @@ func ValidateDistributionSchedule(schedule []ScheduledDistribution) error { // All clearing accounts (including Community) should be in the schedule allClearingAccounts := GetAllClearingAccounts() - seenTimestamps := make(map[uint64]bool) - var lastTime uint64 - for i, period := range schedule { // Validate id is non-zero if period.ID == 0 { return errorsmod.Wrapf(ErrInvalidParam, "period %d: id cannot be zero", i) } - // Validate id is strictly increasing and sequential (each ID = previous + 1). - if i > 0 && period.ID != schedule[i-1].ID+1 { - return errorsmod.Wrapf(ErrInvalidParam, - "period %d: id must be sequential, expected %d but got %d", - i, schedule[i-1].ID+1, period.ID) - } - // Validate timestamp is not zero if period.Timestamp == 0 { return errorsmod.Wrapf(ErrInvalidParam, "period %d: timestamp cannot be zero", i) } - // Check for duplicate timestamps - if seenTimestamps[period.Timestamp] { - return errorsmod.Wrapf(ErrInvalidParam, "period %d: duplicate timestamp", i) - } - seenTimestamps[period.Timestamp] = true - - // Validate schedule is sorted in ascending order - if i > 0 && period.Timestamp <= lastTime { - return errorsmod.Wrapf(ErrInvalidParam, "periods must be sorted by timestamp in ascending order") + // Validate ordering against previous period: IDs must be sequential, timestamps must be monotonically increasing. + if i > 0 { + if period.ID != schedule[i-1].ID+1 { + return errorsmod.Wrapf(ErrInvalidParam, + "period %d: id must be sequential, expected %d but got %d", + i, schedule[i-1].ID+1, period.ID) + } + if period.Timestamp <= schedule[i-1].Timestamp { + return errorsmod.Wrapf(ErrInvalidParam, + "period %d: timestamp must be monotonically increasing, got %d after %d", + i, period.Timestamp, schedule[i-1].Timestamp) + } } - lastTime = period.Timestamp // Validate allocations array is not empty if len(period.Allocations) == 0 { diff --git a/x/pse/types/params_test.go b/x/pse/types/params_test.go index 702d4f16..cd7467b2 100644 --- a/x/pse/types/params_test.go +++ b/x/pse/types/params_test.go @@ -413,7 +413,7 @@ func TestValidateAllocationSchedule(t *testing.T) { }, }, expectErr: true, - errMsg: "duplicate timestamp", + errMsg: "timestamp must be monotonically increasing", }, { name: "invalid_unsorted_schedule", @@ -430,7 +430,7 @@ func TestValidateAllocationSchedule(t *testing.T) { }, }, expectErr: true, - errMsg: "must be sorted by timestamp in ascending order", + errMsg: "timestamp must be monotonically increasing", }, { name: "invalid_empty_allocations_array",