diff --git a/api/cosmos/mint/v1beta1/mint.pulsar.go b/api/cosmos/mint/v1beta1/mint.pulsar.go index 2ad70c1ed755..99895b25532d 100644 --- a/api/cosmos/mint/v1beta1/mint.pulsar.go +++ b/api/cosmos/mint/v1beta1/mint.pulsar.go @@ -10,6 +10,7 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + _ "google.golang.org/protobuf/types/known/anypb" io "io" reflect "reflect" sync "sync" @@ -19,6 +20,7 @@ var ( md_Minter protoreflect.MessageDescriptor fd_Minter_inflation protoreflect.FieldDescriptor fd_Minter_annual_provisions protoreflect.FieldDescriptor + fd_Minter_data protoreflect.FieldDescriptor ) func init() { @@ -26,6 +28,7 @@ func init() { md_Minter = File_cosmos_mint_v1beta1_mint_proto.Messages().ByName("Minter") fd_Minter_inflation = md_Minter.Fields().ByName("inflation") fd_Minter_annual_provisions = md_Minter.Fields().ByName("annual_provisions") + fd_Minter_data = md_Minter.Fields().ByName("data") } var _ protoreflect.Message = (*fastReflection_Minter)(nil) @@ -105,6 +108,12 @@ func (x *fastReflection_Minter) Range(f func(protoreflect.FieldDescriptor, proto return } } + if len(x.Data) != 0 { + value := protoreflect.ValueOfBytes(x.Data) + if !f(fd_Minter_data, value) { + return + } + } } // Has reports whether a field is populated. @@ -124,6 +133,8 @@ func (x *fastReflection_Minter) Has(fd protoreflect.FieldDescriptor) bool { return x.Inflation != "" case "cosmos.mint.v1beta1.Minter.annual_provisions": return x.AnnualProvisions != "" + case "cosmos.mint.v1beta1.Minter.data": + return len(x.Data) != 0 default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.mint.v1beta1.Minter")) @@ -144,6 +155,8 @@ func (x *fastReflection_Minter) Clear(fd protoreflect.FieldDescriptor) { x.Inflation = "" case "cosmos.mint.v1beta1.Minter.annual_provisions": x.AnnualProvisions = "" + case "cosmos.mint.v1beta1.Minter.data": + x.Data = nil default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.mint.v1beta1.Minter")) @@ -166,6 +179,9 @@ func (x *fastReflection_Minter) Get(descriptor protoreflect.FieldDescriptor) pro case "cosmos.mint.v1beta1.Minter.annual_provisions": value := x.AnnualProvisions return protoreflect.ValueOfString(value) + case "cosmos.mint.v1beta1.Minter.data": + value := x.Data + return protoreflect.ValueOfBytes(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.mint.v1beta1.Minter")) @@ -190,6 +206,8 @@ func (x *fastReflection_Minter) Set(fd protoreflect.FieldDescriptor, value proto x.Inflation = value.Interface().(string) case "cosmos.mint.v1beta1.Minter.annual_provisions": x.AnnualProvisions = value.Interface().(string) + case "cosmos.mint.v1beta1.Minter.data": + x.Data = value.Bytes() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.mint.v1beta1.Minter")) @@ -214,6 +232,8 @@ func (x *fastReflection_Minter) Mutable(fd protoreflect.FieldDescriptor) protore panic(fmt.Errorf("field inflation of message cosmos.mint.v1beta1.Minter is not mutable")) case "cosmos.mint.v1beta1.Minter.annual_provisions": panic(fmt.Errorf("field annual_provisions of message cosmos.mint.v1beta1.Minter is not mutable")) + case "cosmos.mint.v1beta1.Minter.data": + panic(fmt.Errorf("field data of message cosmos.mint.v1beta1.Minter is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.mint.v1beta1.Minter")) @@ -231,6 +251,8 @@ func (x *fastReflection_Minter) NewField(fd protoreflect.FieldDescriptor) protor return protoreflect.ValueOfString("") case "cosmos.mint.v1beta1.Minter.annual_provisions": return protoreflect.ValueOfString("") + case "cosmos.mint.v1beta1.Minter.data": + return protoreflect.ValueOfBytes(nil) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.mint.v1beta1.Minter")) @@ -308,6 +330,10 @@ func (x *fastReflection_Minter) ProtoMethods() *protoiface.Methods { if l > 0 { n += 1 + l + runtime.Sov(uint64(l)) } + l = len(x.Data) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -337,6 +363,13 @@ func (x *fastReflection_Minter) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if len(x.Data) > 0 { + i -= len(x.Data) + copy(dAtA[i:], x.Data) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Data))) + i-- + dAtA[i] = 0x1a + } if len(x.AnnualProvisions) > 0 { i -= len(x.AnnualProvisions) copy(dAtA[i:], x.AnnualProvisions) @@ -464,6 +497,40 @@ func (x *fastReflection_Minter) ProtoMethods() *protoiface.Methods { } x.AnnualProvisions = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Data = append(x.Data[:0], dAtA[iNdEx:postIndex]...) + if x.Data == nil { + x.Data = []byte{} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -1310,6 +1377,9 @@ type Minter struct { Inflation string `protobuf:"bytes,1,opt,name=inflation,proto3" json:"inflation,omitempty"` // current annual expected provisions AnnualProvisions string `protobuf:"bytes,2,opt,name=annual_provisions,json=annualProvisions,proto3" json:"annual_provisions,omitempty"` + // data is any custom data that the user might want to put in the minter, to + // be used in the minting process. + Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` } func (x *Minter) Reset() { @@ -1346,6 +1416,13 @@ func (x *Minter) GetAnnualProvisions() string { return "" } +func (x *Minter) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + // Params defines the parameters for the x/mint module. type Params struct { state protoimpl.MessageState @@ -1447,67 +1524,70 @@ var file_cosmos_mint_v1beta1_mint_proto_rawDesc = []byte{ 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x6d, - 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb9, 0x01, 0x0a, 0x06, 0x4d, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x12, 0x4f, 0x0a, 0x09, 0x69, 0x6e, 0x66, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x31, 0xc8, 0xde, 0x1f, 0x00, 0xda, 0xde, 0x1f, - 0x1b, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, - 0x74, 0x68, 0x2e, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x44, 0x65, 0x63, 0xd2, 0xb4, 0x2d, 0x0a, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x44, 0x65, 0x63, 0x52, 0x09, 0x69, 0x6e, 0x66, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5e, 0x0a, 0x11, 0x61, 0x6e, 0x6e, 0x75, 0x61, 0x6c, 0x5f, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x31, 0xc8, 0xde, 0x1f, 0x00, 0xda, 0xde, 0x1f, 0x1b, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x4c, 0x65, 0x67, 0x61, - 0x63, 0x79, 0x44, 0x65, 0x63, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, - 0x44, 0x65, 0x63, 0x52, 0x10, 0x61, 0x6e, 0x6e, 0x75, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb9, 0x04, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x69, 0x6e, 0x74, 0x5f, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x69, 0x6e, 0x74, 0x44, 0x65, 0x6e, 0x6f, 0x6d, 0x12, - 0x6a, 0x0a, 0x15, 0x69, 0x6e, 0x66, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x61, 0x74, - 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x36, + 0x69, 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xcd, 0x01, 0x0a, 0x06, 0x4d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x12, + 0x4f, 0x0a, 0x09, 0x69, 0x6e, 0x66, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x31, 0xc8, 0xde, 0x1f, 0x00, 0xda, 0xde, 0x1f, 0x1b, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x4c, 0x65, + 0x67, 0x61, 0x63, 0x79, 0x44, 0x65, 0x63, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2e, 0x44, 0x65, 0x63, 0x52, 0x09, 0x69, 0x6e, 0x66, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x5e, 0x0a, 0x11, 0x61, 0x6e, 0x6e, 0x75, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x31, 0xc8, 0xde, 0x1f, + 0x00, 0xda, 0xde, 0x1f, 0x1b, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, + 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x44, 0x65, 0x63, + 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x44, 0x65, 0x63, 0x52, 0x10, + 0x61, 0x6e, 0x6e, 0x75, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x22, 0xb9, 0x04, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, + 0x1d, 0x0a, 0x0a, 0x6d, 0x69, 0x6e, 0x74, 0x5f, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x69, 0x6e, 0x74, 0x44, 0x65, 0x6e, 0x6f, 0x6d, 0x12, 0x6a, + 0x0a, 0x15, 0x69, 0x6e, 0x66, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x61, 0x74, 0x65, + 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x36, 0xc8, + 0xde, 0x1f, 0x00, 0xda, 0xde, 0x1f, 0x1b, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, + 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x44, + 0x65, 0x63, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x44, 0x65, 0x63, + 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x13, 0x69, 0x6e, 0x66, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x5b, 0x0a, 0x0d, 0x69, 0x6e, + 0x66, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x36, 0xc8, 0xde, 0x1f, 0x00, 0xda, 0xde, 0x1f, 0x1b, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x4c, 0x65, 0x67, + 0x61, 0x63, 0x79, 0x44, 0x65, 0x63, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x2e, 0x44, 0x65, 0x63, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x0c, 0x69, 0x6e, 0x66, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x12, 0x5b, 0x0a, 0x0d, 0x69, 0x6e, 0x66, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x36, 0xc8, 0xde, 0x1f, 0x00, 0xda, 0xde, 0x1f, 0x1b, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x44, 0x65, 0x63, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x44, 0x65, - 0x63, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x13, 0x69, 0x6e, 0x66, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x5b, 0x0a, 0x0d, 0x69, - 0x6e, 0x66, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x36, 0xc8, 0xde, 0x1f, 0x00, 0xda, 0xde, 0x1f, 0x1b, 0x63, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x4c, 0x65, - 0x67, 0x61, 0x63, 0x79, 0x44, 0x65, 0x63, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2e, 0x44, 0x65, 0x63, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x0c, 0x69, 0x6e, 0x66, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x12, 0x5b, 0x0a, 0x0d, 0x69, 0x6e, 0x66, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x36, 0xc8, 0xde, 0x1f, 0x00, 0xda, 0xde, 0x1f, 0x1b, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, - 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x4c, 0x65, 0x67, 0x61, 0x63, - 0x79, 0x44, 0x65, 0x63, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x44, - 0x65, 0x63, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x0c, 0x69, 0x6e, 0x66, 0x6c, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x4d, 0x69, 0x6e, 0x12, 0x57, 0x0a, 0x0b, 0x67, 0x6f, 0x61, 0x6c, 0x5f, 0x62, 0x6f, - 0x6e, 0x64, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x36, 0xc8, 0xde, 0x1f, 0x00, - 0xda, 0xde, 0x1f, 0x1b, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, - 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x44, 0x65, 0x63, 0xd2, - 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x44, 0x65, 0x63, 0xa8, 0xe7, 0xb0, - 0x2a, 0x01, 0x52, 0x0a, 0x67, 0x6f, 0x61, 0x6c, 0x42, 0x6f, 0x6e, 0x64, 0x65, 0x64, 0x12, 0x26, - 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x79, 0x65, 0x61, - 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x50, - 0x65, 0x72, 0x59, 0x65, 0x61, 0x72, 0x12, 0x4a, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x75, - 0x70, 0x70, 0x6c, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2b, 0xc8, 0xde, 0x1f, 0x00, - 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, - 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x09, 0x6d, 0x61, 0x78, 0x53, 0x75, 0x70, 0x70, - 0x6c, 0x79, 0x3a, 0x1d, 0x8a, 0xe7, 0xb0, 0x2a, 0x18, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, - 0x73, 0x64, 0x6b, 0x2f, 0x78, 0x2f, 0x6d, 0x69, 0x6e, 0x74, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x42, 0xc4, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x2e, 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x09, 0x4d, - 0x69, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x63, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x69, 0x6e, 0x74, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x3b, 0x6d, 0x69, 0x6e, 0x74, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x43, - 0x4d, 0x58, 0xaa, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x4d, 0x69, 0x6e, 0x74, - 0x2e, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x5c, 0x4d, 0x69, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, - 0x1f, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x4d, 0x69, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0xea, 0x02, 0x15, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x4d, 0x69, 0x6e, 0x74, 0x3a, - 0x3a, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x63, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x0c, 0x69, 0x6e, 0x66, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x69, 0x6e, 0x12, 0x57, 0x0a, 0x0b, 0x67, 0x6f, 0x61, 0x6c, 0x5f, 0x62, 0x6f, 0x6e, + 0x64, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x36, 0xc8, 0xde, 0x1f, 0x00, 0xda, + 0xde, 0x1f, 0x1b, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, + 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x44, 0x65, 0x63, 0xd2, 0xb4, + 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x44, 0x65, 0x63, 0xa8, 0xe7, 0xb0, 0x2a, + 0x01, 0x52, 0x0a, 0x67, 0x6f, 0x61, 0x6c, 0x42, 0x6f, 0x6e, 0x64, 0x65, 0x64, 0x12, 0x26, 0x0a, + 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x79, 0x65, 0x61, 0x72, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x50, 0x65, + 0x72, 0x59, 0x65, 0x61, 0x72, 0x12, 0x4a, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x75, 0x70, + 0x70, 0x6c, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2b, 0xc8, 0xde, 0x1f, 0x00, 0xda, + 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, + 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0xd2, 0xb4, 0x2d, 0x0a, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x09, 0x6d, 0x61, 0x78, 0x53, 0x75, 0x70, 0x70, 0x6c, + 0x79, 0x3a, 0x1d, 0x8a, 0xe7, 0xb0, 0x2a, 0x18, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, + 0x64, 0x6b, 0x2f, 0x78, 0x2f, 0x6d, 0x69, 0x6e, 0x74, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x42, 0xc4, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, + 0x6d, 0x69, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x09, 0x4d, 0x69, + 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2f, 0x6d, 0x69, 0x6e, 0x74, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, + 0x6d, 0x69, 0x6e, 0x74, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x4d, + 0x58, 0xaa, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x4d, 0x69, 0x6e, 0x74, 0x2e, + 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x5c, 0x4d, 0x69, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1f, + 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x4d, 0x69, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, + 0x02, 0x15, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x4d, 0x69, 0x6e, 0x74, 0x3a, 0x3a, + 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/simapp/app.go b/simapp/app.go index 35a0c71bc745..348359921049 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -171,7 +171,7 @@ type SimApp struct { ConsensusParamsKeeper consensusparamkeeper.Keeper CircuitKeeper circuitkeeper.Keeper PoolKeeper poolkeeper.Keeper - EpochsKeeper epochskeeper.Keeper + EpochsKeeper *epochskeeper.Keeper // managers ModuleManager *module.Manager diff --git a/simapp/app_di.go b/simapp/app_di.go index 7a459a18507e..d2b27c7eefdc 100644 --- a/simapp/app_di.go +++ b/simapp/app_di.go @@ -93,7 +93,7 @@ type SimApp struct { ConsensusParamsKeeper consensuskeeper.Keeper CircuitBreakerKeeper circuitkeeper.Keeper PoolKeeper poolkeeper.Keeper - EpochsKeeper epochskeeper.Keeper + EpochsKeeper *epochskeeper.Keeper // simulation manager sm *module.SimulationManager @@ -111,7 +111,8 @@ func init() { // AppConfig returns the default app config. func AppConfig() depinject.Config { return depinject.Configs( - appConfig, // Alternatively use appconfig.LoadYAML(AppConfigYAML) + appConfig, // Alternatively use appconfig.LoadYAML(AppConfigYAML) + depinject.Provide(ProvideExampleMintFn), // optional: override the mint module's mint function with epoched minting ) } @@ -174,8 +175,7 @@ func NewSimApp( // // For providing a custom inflation function for x/mint add here your - // custom function that implements the minttypes.InflationCalculationFn - // interface. + // custom function that implements the minttypes.MintFn interface. ), ) ) diff --git a/simapp/go.mod b/simapp/go.mod index 46e39f69b058..0e49796e23c6 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -19,7 +19,7 @@ require ( cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 cosmossdk.io/x/circuit v0.0.0-20230613133644-0a778132a60f cosmossdk.io/x/distribution v0.0.0-20240227221813-a248d05f70f4 - cosmossdk.io/x/epochs v0.0.0-00010101000000-000000000000 + cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 cosmossdk.io/x/evidence v0.0.0-20230613133644-0a778132a60f cosmossdk.io/x/feegrant v0.0.0-20230613133644-0a778132a60f cosmossdk.io/x/gov v0.0.0-20231113122742-912390d5fc4a diff --git a/simapp/mint_fn.go b/simapp/mint_fn.go new file mode 100644 index 000000000000..e34aca38f496 --- /dev/null +++ b/simapp/mint_fn.go @@ -0,0 +1,125 @@ +package simapp + +import ( + "context" + "encoding/binary" + + "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/event" + "cosmossdk.io/math" + authtypes "cosmossdk.io/x/auth/types" + banktypes "cosmossdk.io/x/bank/types" + minttypes "cosmossdk.io/x/mint/types" + stakingtypes "cosmossdk.io/x/staking/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type MintBankKeeper interface { + MintCoins(ctx context.Context, moduleName string, coins sdk.Coins) error + SendCoinsFromModuleToModule(ctx context.Context, senderModule string, recipientModule string, amt sdk.Coins) error +} + +// ProvideExampleMintFn returns the function used in x/mint's endblocker to mint new tokens. +// Note that this function can not have the mint keeper as a parameter because it would create a cyclic dependency. +func ProvideExampleMintFn(bankKeeper MintBankKeeper) minttypes.MintFn { + return func(ctx context.Context, env appmodule.Environment, minter *minttypes.Minter, epochID string, epochNumber int64) error { + // in this example we ignore epochNumber as we don't care what epoch we are in, we just assume we are being called every minute. + if epochID != "minute" { + return nil + } + + var stakingParams stakingtypes.QueryParamsResponse + err := env.QueryRouterService.InvokeTyped(ctx, &stakingtypes.QueryParamsRequest{}, &stakingParams) + if err != nil { + return err + } + + var bankSupply banktypes.QuerySupplyOfResponse + err = env.QueryRouterService.InvokeTyped(ctx, &banktypes.QuerySupplyOfRequest{Denom: stakingParams.Params.BondDenom}, &bankSupply) + if err != nil { + return err + } + stakingTokenSupply := bankSupply.Amount + + var mintParams minttypes.QueryParamsResponse + err = env.QueryRouterService.InvokeTyped(ctx, &minttypes.QueryParamsRequest{}, &mintParams) + if err != nil { + return err + } + + var stakingPool stakingtypes.QueryPoolResponse + err = env.QueryRouterService.InvokeTyped(ctx, &stakingtypes.QueryPoolRequest{}, &stakingPool) + if err != nil { + return err + } + + // bondedRatio + bondedRatio := math.LegacyNewDecFromInt(stakingPool.Pool.BondedTokens).QuoInt(stakingTokenSupply.Amount) + minter.Inflation = minter.NextInflationRate(mintParams.Params, bondedRatio) + minter.AnnualProvisions = minter.NextAnnualProvisions(mintParams.Params, stakingTokenSupply.Amount) + + // to get a more accurate amount of tokens minted, we get, and later store, last minting time. + + // if this is the first time minting, we initialize the minter.Data with the current time - 60s + // to mint tokens at the beginning. Note: this is a custom behavior to avoid breaking tests. + if minter.Data == nil { + minter.Data = make([]byte, 8) + binary.BigEndian.PutUint64(minter.Data, (uint64)(env.HeaderService.HeaderInfo(ctx).Time.Unix()-60)) + } + + lastMint := binary.BigEndian.Uint64(minter.Data) + binary.BigEndian.PutUint64(minter.Data, (uint64)(env.HeaderService.HeaderInfo(ctx).Time.Unix())) + + // calculate the amount of tokens to mint, based on the time since the last mint + secsSinceLastMint := env.HeaderService.HeaderInfo(ctx).Time.Unix() - (int64)(lastMint) + provisionAmt := minter.AnnualProvisions.QuoInt64(31536000).MulInt64(secsSinceLastMint) // 31536000 = seconds in a year + mintedCoin := sdk.NewCoin(mintParams.Params.MintDenom, provisionAmt.TruncateInt()) + maxSupply := mintParams.Params.MaxSupply + totalSupply := stakingTokenSupply.Amount + + if !maxSupply.IsZero() { + // supply is not infinite, check the amount to mint + remainingSupply := maxSupply.Sub(totalSupply) + + if remainingSupply.LTE(math.ZeroInt()) { + // max supply reached, no new tokens will be minted + // also handles the case where totalSupply > maxSupply + return nil + } + + // if the amount to mint is greater than the remaining supply, mint the remaining supply + if mintedCoin.Amount.GT(remainingSupply) { + mintedCoin.Amount = remainingSupply + } + } + + if mintedCoin.Amount.IsZero() { + // skip as no coins need to be minted + return nil + } + + mintedCoins := sdk.NewCoins(mintedCoin) + if err := bankKeeper.MintCoins(ctx, minttypes.ModuleName, mintedCoins); err != nil { + return err + } + + // Example of custom send while minting + // Send some tokens to a "team account" + // if err = bankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, ... ); err != nil { + // return err + // } + + if err = bankKeeper.SendCoinsFromModuleToModule(ctx, minttypes.ModuleName, authtypes.FeeCollectorName, mintedCoins); err != nil { + return err + } + + return env.EventService.EventManager(ctx).EmitKV( + minttypes.EventTypeMint, + event.NewAttribute(minttypes.AttributeKeyBondedRatio, bondedRatio.String()), + event.NewAttribute(minttypes.AttributeKeyInflation, minter.Inflation.String()), + event.NewAttribute(minttypes.AttributeKeyAnnualProvisions, minter.AnnualProvisions.String()), + event.NewAttribute(sdk.AttributeKeyAmount, mintedCoin.Amount.String()), + ) + } +} diff --git a/tests/e2e/bank/grpc.go b/tests/e2e/bank/grpc.go index 3f17667a4aa5..29f57bc4ae84 100644 --- a/tests/e2e/bank/grpc.go +++ b/tests/e2e/bank/grpc.go @@ -35,7 +35,7 @@ func (s *E2ETestSuite) TestTotalSupplyGRPCHandler() { &types.QueryTotalSupplyResponse{ Supply: sdk.NewCoins( sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), s.cfg.AccountTokens), - sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(3))), + sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(47))), ), Pagination: &query.PageResponse{ Total: 2, @@ -50,7 +50,7 @@ func (s *E2ETestSuite) TestTotalSupplyGRPCHandler() { }, &types.QuerySupplyOfResponse{}, &types.QuerySupplyOfResponse{ - Amount: sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(3))), + Amount: sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(47))), }, }, { @@ -61,7 +61,7 @@ func (s *E2ETestSuite) TestTotalSupplyGRPCHandler() { }, &types.QuerySupplyOfResponse{}, &types.QuerySupplyOfResponse{ - Amount: sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(6))), + Amount: sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(47))), }, }, { @@ -72,7 +72,7 @@ func (s *E2ETestSuite) TestTotalSupplyGRPCHandler() { }, &types.QuerySupplyOfResponse{}, &types.QuerySupplyOfResponse{ - Amount: sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(3))), + Amount: sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(47))), }, }, { diff --git a/tests/e2e/distribution/grpc_query_suite.go b/tests/e2e/distribution/grpc_query_suite.go index d90a74988aa8..4a5a2c3475b8 100644 --- a/tests/e2e/distribution/grpc_query_suite.go +++ b/tests/e2e/distribution/grpc_query_suite.go @@ -116,7 +116,7 @@ func (s *GRPCQueryTestSuite) TestQueryOutstandingRewardsGRPC() { val := s.network.GetValidators()[0] baseURL := val.GetAPIAddress() - rewards, err := sdk.ParseDecCoins("5.88stake") + rewards, err := sdk.ParseDecCoins("46.06stake") s.Require().NoError(err) testCases := []struct { @@ -170,7 +170,7 @@ func (s *GRPCQueryTestSuite) TestQueryValidatorCommissionGRPC() { val := s.network.GetValidators()[0] baseURL := val.GetAPIAddress() - commission, err := sdk.ParseDecCoins("2.94stake") + commission, err := sdk.ParseDecCoins("23.03stake") s.Require().NoError(err) testCases := []struct { @@ -283,7 +283,7 @@ func (s *GRPCQueryTestSuite) TestQueryDelegatorRewardsGRPC() { val := s.network.GetValidators()[0] baseURL := val.GetAPIAddress() - rewards, err := sdk.ParseDecCoins("2.94stake") + rewards, err := sdk.ParseDecCoins("23.03stake") s.Require().NoError(err) testCases := []struct { diff --git a/tests/go.mod b/tests/go.mod index c32b5d0d4492..606bab894402 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -65,7 +65,7 @@ require ( cosmossdk.io/client/v2 v2.0.0-20230630094428-02b760776860 // indirect cosmossdk.io/core/testing v0.0.0-00010101000000-000000000000 // indirect cosmossdk.io/x/circuit v0.0.0-20230613133644-0a778132a60f // indirect - cosmossdk.io/x/epochs v0.0.0-00010101000000-000000000000 // indirect + cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/epochs/depinject.go b/x/epochs/depinject.go index 0239cc0081a6..f09f9f95d9f8 100644 --- a/x/epochs/depinject.go +++ b/x/epochs/depinject.go @@ -39,7 +39,7 @@ type ModuleInputs struct { type ModuleOutputs struct { depinject.Out - EpochKeeper keeper.Keeper + EpochKeeper *keeper.Keeper Module appmodule.AppModule } @@ -49,7 +49,7 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { return ModuleOutputs{EpochKeeper: k, Module: m} } -func InvokeSetHooks(keeper keeper.Keeper, hooks map[string]types.EpochHooksWrapper) error { +func InvokeSetHooks(keeper *keeper.Keeper, hooks map[string]types.EpochHooksWrapper) error { if hooks == nil { return nil } diff --git a/x/epochs/keeper/epoch_test.go b/x/epochs/keeper/epoch_test.go index 0977940afeca..24dcc4764042 100644 --- a/x/epochs/keeper/epoch_test.go +++ b/x/epochs/keeper/epoch_test.go @@ -93,9 +93,10 @@ func (s *KeeperTestSuite) TestEpochLifeCycle() { allEpochs, err := s.EpochsKeeper.AllEpochInfos(s.Ctx) s.Require().NoError(err) - s.Require().Len(allEpochs, 4) + s.Require().Len(allEpochs, 5) s.Require().Equal(allEpochs[0].Identifier, "day") // alphabetical order s.Require().Equal(allEpochs[1].Identifier, "hour") - s.Require().Equal(allEpochs[2].Identifier, "monthly") - s.Require().Equal(allEpochs[3].Identifier, "week") + s.Require().Equal(allEpochs[2].Identifier, "minute") + s.Require().Equal(allEpochs[3].Identifier, "monthly") + s.Require().Equal(allEpochs[4].Identifier, "week") } diff --git a/x/epochs/keeper/genesis_test.go b/x/epochs/keeper/genesis_test.go index 4400cb65908f..eb42f17246c8 100644 --- a/x/epochs/keeper/genesis_test.go +++ b/x/epochs/keeper/genesis_test.go @@ -18,7 +18,7 @@ func TestEpochsExportGenesis(t *testing.T) { genesis, err := epochsKeeper.ExportGenesis(ctx) require.NoError(t, err) - require.Len(t, genesis.Epochs, 3) + require.Len(t, genesis.Epochs, 4) expectedEpochs := types.DefaultGenesis().Epochs for i := 0; i < len(expectedEpochs); i++ { diff --git a/x/epochs/keeper/grpc_query_test.go b/x/epochs/keeper/grpc_query_test.go index 760c0e978bc2..e83b11e2d1fe 100644 --- a/x/epochs/keeper/grpc_query_test.go +++ b/x/epochs/keeper/grpc_query_test.go @@ -11,7 +11,7 @@ func (s *KeeperTestSuite) TestQueryEpochInfos() { // Check that querying epoch infos on default genesis returns the default genesis epoch infos epochInfosResponse, err := queryClient.EpochInfos(s.Ctx, &types.QueryEpochsInfoRequest{}) s.Require().NoError(err) - s.Require().Len(epochInfosResponse.Epochs, 3) + s.Require().Len(epochInfosResponse.Epochs, 4) expectedEpochs := types.DefaultGenesis().Epochs for id := range expectedEpochs { expectedEpochs[id].StartTime = s.Ctx.BlockTime() diff --git a/x/epochs/keeper/keeper.go b/x/epochs/keeper/keeper.go index 2b47d40be2b9..c15ed267e989 100644 --- a/x/epochs/keeper/keeper.go +++ b/x/epochs/keeper/keeper.go @@ -19,7 +19,7 @@ type Keeper struct { } // NewKeeper returns a new keeper by codec and storeKey inputs. -func NewKeeper(env appmodule.Environment, cdc codec.BinaryCodec) Keeper { +func NewKeeper(env appmodule.Environment, cdc codec.BinaryCodec) *Keeper { sb := collections.NewSchemaBuilder(env.KVStoreService) k := Keeper{ Environment: env, @@ -32,11 +32,11 @@ func NewKeeper(env appmodule.Environment, cdc codec.BinaryCodec) Keeper { panic(err) } k.Schema = schema - return k + return &k } // Set the gamm hooks. -func (k Keeper) SetHooks(eh types.EpochHooks) Keeper { +func (k *Keeper) SetHooks(eh types.EpochHooks) *Keeper { if k.hooks != nil { panic("cannot set epochs hooks twice") } diff --git a/x/epochs/keeper/keeper_test.go b/x/epochs/keeper/keeper_test.go index 354669f76a61..07cc9a35eb16 100644 --- a/x/epochs/keeper/keeper_test.go +++ b/x/epochs/keeper/keeper_test.go @@ -27,7 +27,7 @@ type KeeperTestSuite struct { suite.Suite Ctx sdk.Context environment appmodule.Environment - EpochsKeeper epochskeeper.Keeper + EpochsKeeper *epochskeeper.Keeper queryClient types.QueryClient } @@ -39,7 +39,7 @@ func (s *KeeperTestSuite) SetupTest() { s.environment = environment queryRouter := baseapp.NewGRPCQueryRouter() cfg := module.NewConfigurator(nil, nil, queryRouter) - types.RegisterQueryServer(cfg.QueryServer(), epochskeeper.NewQuerier(s.EpochsKeeper)) + types.RegisterQueryServer(cfg.QueryServer(), epochskeeper.NewQuerier(*s.EpochsKeeper)) grpcQueryService := &baseapp.QueryServiceTestHelper{ GRPCQueryRouter: queryRouter, Ctx: s.Ctx, @@ -49,7 +49,7 @@ func (s *KeeperTestSuite) SetupTest() { s.queryClient = types.NewQueryClient(grpcQueryService) } -func Setup(t *testing.T) (sdk.Context, epochskeeper.Keeper, appmodule.Environment) { +func Setup(t *testing.T) (sdk.Context, *epochskeeper.Keeper, appmodule.Environment) { t.Helper() key := storetypes.NewKVStoreKey(types.StoreKey) @@ -67,7 +67,7 @@ func Setup(t *testing.T) (sdk.Context, epochskeeper.Keeper, appmodule.Environmen ctx.WithHeaderInfo(header.Info{Height: 1, Time: time.Now().UTC(), ChainID: "epochs"}) err := epochsKeeper.InitGenesis(ctx, *types.DefaultGenesis()) require.NoError(t, err) - SetEpochStartTime(ctx, epochsKeeper) + SetEpochStartTime(ctx, *epochsKeeper) return ctx, epochsKeeper, environment } diff --git a/x/epochs/module.go b/x/epochs/module.go index 23f39c362075..8365f189cfa2 100644 --- a/x/epochs/module.go +++ b/x/epochs/module.go @@ -36,11 +36,11 @@ const ConsensusVersion = 1 // AppModule implements the AppModule interface for the epochs module. type AppModule struct { cdc codec.Codec - keeper keeper.Keeper + keeper *keeper.Keeper } // NewAppModule creates a new AppModule object. -func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule { +func NewAppModule(cdc codec.Codec, keeper *keeper.Keeper) AppModule { return AppModule{ cdc: cdc, keeper: keeper, @@ -67,7 +67,7 @@ func (AppModule) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *gwrunt // RegisterServices registers module services. func (am AppModule) RegisterServices(registrar grpc.ServiceRegistrar) error { - types.RegisterQueryServer(registrar, keeper.NewQuerier(am.keeper)) + types.RegisterQueryServer(registrar, keeper.NewQuerier(*am.keeper)) return nil } diff --git a/x/epochs/types/genesis.go b/x/epochs/types/genesis.go index cf60354782b1..1cdea892df49 100644 --- a/x/epochs/types/genesis.go +++ b/x/epochs/types/genesis.go @@ -17,6 +17,7 @@ func DefaultGenesis() *GenesisState { epochs := []EpochInfo{ NewGenesisEpochInfo("day", time.Hour*24), // alphabetical order NewGenesisEpochInfo("hour", time.Hour), + NewGenesisEpochInfo("minute", time.Minute), NewGenesisEpochInfo("week", time.Hour*24*7), } return NewGenesisState(epochs) diff --git a/x/group/go.mod b/x/group/go.mod index 49d909ae2463..ce0ad4f7500b 100644 --- a/x/group/go.mod +++ b/x/group/go.mod @@ -44,6 +44,7 @@ require ( cosmossdk.io/collections v0.4.0 // indirect cosmossdk.io/core/testing v0.0.0-00010101000000-000000000000 // indirect cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5 // indirect + cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 // indirect cosmossdk.io/x/tx v0.13.3 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect diff --git a/x/group/go.sum b/x/group/go.sum index d9cc54575ff2..c4d6d9369dfe 100644 --- a/x/group/go.sum +++ b/x/group/go.sum @@ -12,6 +12,8 @@ cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc h1:R9O9d75e0qZYUsVV0zzi+ cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc/go.mod h1:amTTatOUV3u1PsKmNb87z6/galCxrRbz9kRdJkL0DyU= cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5 h1:eb0kcGyaYHSS0do7+MIWg7UKlskSH01biRNENbm/zDA= cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5/go.mod h1:drzY4oVisyWvSgpsM7ccQ7IX3efMuVIvd9Eij1Gm/6o= +cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 h1:GuBrfHsK3RD5vlD4DuBz3DXslR6VlnzrYmHOC3L679Q= +cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337/go.mod h1:PhLn1pMBilyRC4GfRkoYhm+XVAYhF4adVrzut8AdpJI= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= diff --git a/x/mint/CHANGELOG.md b/x/mint/CHANGELOG.md index ad9b78b53ed1..014ac8759a9d 100644 --- a/x/mint/CHANGELOG.md +++ b/x/mint/CHANGELOG.md @@ -27,12 +27,14 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features -* [19896](https://github.com/cosmos/cosmos-sdk/pull/19896) Added a new max supply genesis param to existing params. +* [#20363](https://github.com/cosmos/cosmos-sdk/pull/20363) Implemented epoched minting, configurable through `MintFn`. Now `MintFn` doesn't do any assumptions on how tokens are minted, users can define their own minting logic. +* [#19896](https://github.com/cosmos/cosmos-sdk/pull/19896) Added a new max supply genesis param to existing params. ### Improvements ### API Breaking Changes +* [#20363](https://github.com/cosmos/cosmos-sdk/pull/20363) Deprecated InflationCalculationFn in favor of MintFn, `keeper.DefaultMintFn` wrapper must be used in order to continue using it in `NewAppModule`. This is not breaking for depinject users, as both `MintFn` and `InflationCalculationFn` are accepted. * [#19367](https://github.com/cosmos/cosmos-sdk/pull/19398) `appmodule.Environment` is received on the Keeper to get access to different application services ### Bug Fixes diff --git a/x/mint/README.md b/x/mint/README.md index 0d16ce208268..aac6d52ff686 100644 --- a/x/mint/README.md +++ b/x/mint/README.md @@ -6,10 +6,15 @@ sidebar_position: 1 ## Contents +* [Concepts](#concepts) + * [The Minting Mechanism](#the-minting-mechanism) * [State](#state) * [Minter](#minter) * [Params](#params) -* [Begin-Block](#begin-block) +* [Epoch minting](#epoch-minting) + * [MintFn](#mintfn) +* [Block based minting](#block-based-minting) + * [Default configuration](#default-configuration) * [NextInflationRate](#nextinflationrate) * [NextAnnualProvisions](#nextannualprovisions) * [BlockProvision](#blockprovision) @@ -51,12 +56,13 @@ It can be broken down in the following way: ### Minter -The minter is a space for holding current inflation information. +The minter is a space for holding current inflation information and any other data +related to minting (in the `data` field) * Minter: `0x00 -> ProtocolBuffer(minter)` ```protobuf reference -https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/mint/v1beta1/mint.proto#L10-L24 +https://github.com/cosmos/cosmos-sdk/blob/ace7bca105a8d5363782cfd19c6f169b286cd3b2/x/mint/proto/cosmos/mint/v1beta1/mint.proto#L11-L29 ``` ### Params @@ -72,11 +78,43 @@ A value of `0` indicates an unlimited supply. https://github.com/cosmos/cosmos-sdk/blob/7068d0da52d954430054768b2c56aff44666933b/x/mint/proto/cosmos/mint/v1beta1/mint.proto#L26-L68 ``` -## Begin-Block +## Epoch minting -Minting parameters are recalculated and inflation paid at the beginning of each block. +In the latest release of x/mint, the minting logic has been refactored to allow for more flexibility in the minting process. The `InflationCalculationFn` has been deprecated in favor of `MintFn`. The `MintFn` function is passed to the `NewAppModule` function and is used to mint tokens on the configured epoch beginning. This change allows users to define their own minting logic and removes any assumptions on how tokens are minted. -The minting logic in the `BeginBlocker` function provides an optional feature for controlling token minting based on the maximum allowable supply (MaxSupply). This feature allows users to adjust the minting process according to their specific requirements and use cases. However, it's important to note that the MaxSupply parameter is independent of the minting process and assumes that any adjustments to the total supply, including burning tokens, are handled by external modules. +```mermaid +flowchart LR + A[BeforeEpochStart] --> B[MintFn] + + subgraph B["MintFn (user defined)"] + direction LR + C[Get x/staking info] --> D[Calculate Inflation] + D --> E[Mint Tokens] + end +``` + +### MintFn + +The `MintFn` function is called at the beginning of each epoch and is responsible for minting tokens. The function signature is as follows: + +```go +type MintFn func(ctx context.Context, env appmodule.Environment, minter *Minter, epochId string, epochNumber int64) error +``` + +How this function mints tokens is defined by the app developers, meaning they can query state and perform any calculations they deem necessary. [This implementation](https://github.com/cosmos/cosmos-sdk/blob/ace7bca105a8d5363782cfd19c6f169b286cd3b2/simapp/mint_fn.go#L25) in SimApp contains examples of how to use `QueryRouterService` and the Minter's `data`. + +:::warning +Note that BeginBlock will keep calling the MintFn for every block, so it is important to ensure that MintFn returns early if the epoch ID does not match the expected one. +::: + + +## Block based minting + +In addition to minting based on epoch, minting based on block is also possible. This is achieved through calling the `MintFn` in `BeginBlock` with an epochID and epochNumber of `"block"` and `-1`, respectively. + +### Default configuration + +If no `MintFn` is passed to the `NewAppModule` function, the minting logic defaults to block-based minting, corresponding to `mintKeeper.DefaultMintFn(types.DefaultInflationCalculationFn)`. ### Inflation rate calculation diff --git a/x/mint/depinject.go b/x/mint/depinject.go index 556a7c4b7a81..4b430f0e8052 100644 --- a/x/mint/depinject.go +++ b/x/mint/depinject.go @@ -6,6 +6,7 @@ import ( "cosmossdk.io/depinject" "cosmossdk.io/depinject/appconfig" authtypes "cosmossdk.io/x/auth/types" + epochstypes "cosmossdk.io/x/epochs/types" "cosmossdk.io/x/mint/keeper" "cosmossdk.io/x/mint/types" @@ -30,7 +31,8 @@ type ModuleInputs struct { Config *modulev1.Module Environment appmodule.Environment Cdc codec.Codec - InflationCalculationFn types.InflationCalculationFn `optional:"true"` + MintFn types.MintFn `optional:"true"` + InflationCalculationFn types.InflationCalculationFn `optional:"true"` // deprecated AccountKeeper types.AccountKeeper BankKeeper types.BankKeeper @@ -42,6 +44,7 @@ type ModuleOutputs struct { MintKeeper keeper.Keeper Module appmodule.AppModule + EpochHooks epochstypes.EpochHooksWrapper } func ProvideModule(in ModuleInputs) ModuleOutputs { @@ -71,8 +74,21 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { as, ) - // when no inflation calculation function is provided it will use the default types.DefaultInflationCalculationFn - m := NewAppModule(in.Cdc, k, in.AccountKeeper, in.InflationCalculationFn) + if in.MintFn != nil && in.InflationCalculationFn != nil { + panic("MintFn and InflationCalculationFn cannot both be set") + } + + // if no mintFn is provided, use the default minting function + if in.MintFn == nil { + // if no inflationCalculationFn is provided, use the default inflation calculation function + if in.InflationCalculationFn == nil { + in.InflationCalculationFn = types.DefaultInflationCalculationFn + } + + in.MintFn = k.DefaultMintFn(in.InflationCalculationFn) + } + + m := NewAppModule(in.Cdc, k, in.AccountKeeper, in.MintFn) - return ModuleOutputs{MintKeeper: k, Module: m} + return ModuleOutputs{MintKeeper: k, Module: m, EpochHooks: epochstypes.EpochHooksWrapper{EpochHooks: m}} } diff --git a/x/mint/epoch_hooks.go b/x/mint/epoch_hooks.go new file mode 100644 index 000000000000..28ae5a26b195 --- /dev/null +++ b/x/mint/epoch_hooks.go @@ -0,0 +1,34 @@ +package mint + +import ( + "context" + + epochstypes "cosmossdk.io/x/epochs/types" +) + +var _ epochstypes.EpochHooks = AppModule{} + +// GetModuleName implements types.EpochHooks. +func (am AppModule) GetModuleName() string { + return am.Name() +} + +// BeforeEpochStart calls the mint function. +func (am AppModule) BeforeEpochStart(ctx context.Context, epochIdentifier string, epochNumber int64) error { + minter, err := am.keeper.Minter.Get(ctx) + if err != nil { + return err + } + + err = am.mintFn(ctx, am.keeper.Environment, &minter, epochIdentifier, epochNumber) + if err != nil { + return err + } + + return am.keeper.Minter.Set(ctx, minter) +} + +// AfterEpochEnd is a noop +func (am AppModule) AfterEpochEnd(ctx context.Context, epochIdentifier string, epochNumber int64) error { + return nil +} diff --git a/x/mint/go.mod b/x/mint/go.mod index e1f4b0861275..9c7c08e552eb 100644 --- a/x/mint/go.mod +++ b/x/mint/go.mod @@ -12,6 +12,7 @@ require ( cosmossdk.io/math v1.3.0 cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc cosmossdk.io/x/accounts v0.0.0-20240226161501-23359a0b6d91 // indirect + cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 github.com/cosmos/cosmos-sdk v0.51.0 diff --git a/x/mint/go.sum b/x/mint/go.sum index ca4e47166b63..3d8b9af73759 100644 --- a/x/mint/go.sum +++ b/x/mint/go.sum @@ -14,6 +14,8 @@ cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc h1:R9O9d75e0qZYUsVV0zzi+ cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc/go.mod h1:amTTatOUV3u1PsKmNb87z6/galCxrRbz9kRdJkL0DyU= cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5 h1:eb0kcGyaYHSS0do7+MIWg7UKlskSH01biRNENbm/zDA= cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5/go.mod h1:drzY4oVisyWvSgpsM7ccQ7IX3efMuVIvd9Eij1Gm/6o= +cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 h1:GuBrfHsK3RD5vlD4DuBz3DXslR6VlnzrYmHOC3L679Q= +cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337/go.mod h1:PhLn1pMBilyRC4GfRkoYhm+XVAYhF4adVrzut8AdpJI= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= diff --git a/x/mint/keeper/abci.go b/x/mint/keeper/abci.go index 9c8ec7261262..8fbeb4050f83 100644 --- a/x/mint/keeper/abci.go +++ b/x/mint/keeper/abci.go @@ -3,15 +3,13 @@ package keeper import ( "context" - "cosmossdk.io/core/event" "cosmossdk.io/x/mint/types" "github.com/cosmos/cosmos-sdk/telemetry" - sdk "github.com/cosmos/cosmos-sdk/types" ) // BeginBlocker mints new tokens for the previous block. -func (k Keeper) BeginBlocker(ctx context.Context, ic types.InflationCalculationFn) error { +func (k Keeper) BeginBlocker(ctx context.Context, mintFn types.MintFn) error { defer telemetry.ModuleMeasureSince(types.ModuleName, telemetry.Now(), telemetry.MetricKeyBeginBlocker) // fetch stored minter & params @@ -20,76 +18,12 @@ func (k Keeper) BeginBlocker(ctx context.Context, ic types.InflationCalculationF return err } - params, err := k.Params.Get(ctx) + // we pass -1 as epoch number to indicate that this is not an epoch minting, + // but a regular block minting. Same with epoch id "block". + err = mintFn(ctx, k.Environment, &minter, "block", -1) if err != nil { return err } - // recalculate inflation rate - totalStakingSupply, err := k.StakingTokenSupply(ctx) - if err != nil { - return err - } - - bondedRatio, err := k.BondedRatio(ctx) - if err != nil { - return err - } - - // update minter's inflation and annual provisions - minter.Inflation = ic(ctx, minter, params, bondedRatio) - minter.AnnualProvisions = minter.NextAnnualProvisions(params, totalStakingSupply) - if err = k.Minter.Set(ctx, minter); err != nil { - return err - } - - // calculate minted coins - mintedCoin := minter.BlockProvision(params) - mintedCoins := sdk.NewCoins(mintedCoin) - - maxSupply := params.MaxSupply - totalSupply := k.bankKeeper.GetSupply(ctx, params.MintDenom).Amount // fetch total supply from the bank module - - // if maxSupply is not infinite, check against max_supply parameter - if !maxSupply.IsZero() { - if totalSupply.Add(mintedCoins.AmountOf(params.MintDenom)).GT(maxSupply) { - // calculate the difference between maxSupply and totalSupply - diff := maxSupply.Sub(totalSupply) - // mint the difference - diffCoin := sdk.NewCoin(params.MintDenom, diff) - diffCoins := sdk.NewCoins(diffCoin) - - // mint coins - if err := k.MintCoins(ctx, diffCoins); err != nil { - return err - } - mintedCoins = diffCoins - } - } - - // mint coins if maxSupply is infinite or total staking supply is less than maxSupply - if maxSupply.IsZero() || totalSupply.Add(mintedCoins.AmountOf(params.MintDenom)).LT(maxSupply) { - // mint coins - if err := k.MintCoins(ctx, mintedCoins); err != nil { - return err - } - } - - // send the minted coins to the fee collector account - err = k.AddCollectedFees(ctx, mintedCoins) - if err != nil { - return err - } - - if mintedCoin.Amount.IsInt64() { - defer telemetry.ModuleSetGauge(types.ModuleName, float32(mintedCoin.Amount.Int64()), "minted_tokens") - } - - return k.EventService.EventManager(ctx).EmitKV( - types.EventTypeMint, - event.NewAttribute(types.AttributeKeyBondedRatio, bondedRatio.String()), - event.NewAttribute(types.AttributeKeyInflation, minter.Inflation.String()), - event.NewAttribute(types.AttributeKeyAnnualProvisions, minter.AnnualProvisions.String()), - event.NewAttribute(sdk.AttributeKeyAmount, mintedCoin.Amount.String()), - ) + return k.Minter.Set(ctx, minter) } diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index f7306a131bea..3f31a3ff3252 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -6,11 +6,13 @@ import ( "cosmossdk.io/collections" "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/event" "cosmossdk.io/log" "cosmossdk.io/math" "cosmossdk.io/x/mint/types" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -101,3 +103,85 @@ func (k Keeper) MintCoins(ctx context.Context, newCoins sdk.Coins) error { func (k Keeper) AddCollectedFees(ctx context.Context, fees sdk.Coins) error { return k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, k.feeCollectorName, fees) } + +func (k Keeper) DefaultMintFn(ic types.InflationCalculationFn) types.MintFn { + return func(ctx context.Context, env appmodule.Environment, minter *types.Minter, epochId string, epochNumber int64) error { + // the default mint function is called every block, so we only check if epochId is "block" which is + // a special value to indicate that this is not an epoch minting, but a regular block minting. + if epochId != "block" { + return nil + } + + stakingTokenSupply, err := k.StakingTokenSupply(ctx) + if err != nil { + return err + } + + bondedRatio, err := k.BondedRatio(ctx) + if err != nil { + return err + } + + params, err := k.Params.Get(ctx) + if err != nil { + return err + } + + minter.Inflation = ic(ctx, *minter, params, bondedRatio) + minter.AnnualProvisions = minter.NextAnnualProvisions(params, stakingTokenSupply) + + mintedCoin := minter.BlockProvision(params) + mintedCoins := sdk.NewCoins(mintedCoin) + maxSupply := params.MaxSupply + totalSupply := stakingTokenSupply + + // if maxSupply is not infinite, check against max_supply parameter + if !maxSupply.IsZero() { + if totalSupply.Add(mintedCoins.AmountOf(params.MintDenom)).GT(maxSupply) { + // calculate the difference between maxSupply and totalSupply + diff := maxSupply.Sub(totalSupply) + if diff.LTE(math.ZeroInt()) { + k.logger.Info("max supply reached, no new tokens will be minted") + return nil + } + + // mint the difference + diffCoin := sdk.NewCoin(params.MintDenom, diff) + diffCoins := sdk.NewCoins(diffCoin) + + // mint coins + if err := k.MintCoins(ctx, diffCoins); err != nil { + return err + } + mintedCoins = diffCoins + } + } + + // mint coins if maxSupply is infinite or total staking supply is less than maxSupply + if maxSupply.IsZero() || totalSupply.Add(mintedCoins.AmountOf(params.MintDenom)).LT(maxSupply) { + // mint coins + if err := k.MintCoins(ctx, mintedCoins); err != nil { + return err + } + } + + // send the minted coins to the fee collector account + // TODO: figure out a better way to do this + err = k.AddCollectedFees(ctx, mintedCoins) + if err != nil { + return err + } + + if mintedCoin.Amount.IsInt64() { + defer telemetry.ModuleSetGauge(types.ModuleName, float32(mintedCoin.Amount.Int64()), "minted_tokens") + } + + return env.EventService.EventManager(ctx).EmitKV( + types.EventTypeMint, + event.NewAttribute(types.AttributeKeyBondedRatio, bondedRatio.String()), + event.NewAttribute(types.AttributeKeyInflation, minter.Inflation.String()), + event.NewAttribute(types.AttributeKeyAnnualProvisions, minter.AnnualProvisions.String()), + event.NewAttribute(sdk.AttributeKeyAmount, mintedCoin.Amount.String()), + ) + } +} diff --git a/x/mint/keeper/keeper_test.go b/x/mint/keeper/keeper_test.go index e5ddd1b0d469..971ce5c830b1 100644 --- a/x/mint/keeper/keeper_test.go +++ b/x/mint/keeper/keeper_test.go @@ -24,7 +24,7 @@ import ( const govModuleNameStr = "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn" -type IntegrationTestSuite struct { +type KeeperTestSuite struct { suite.Suite mintKeeper keeper.Keeper @@ -35,10 +35,10 @@ type IntegrationTestSuite struct { } func TestKeeperTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) + suite.Run(t, new(KeeperTestSuite)) } -func (s *IntegrationTestSuite) SetupTest() { +func (s *KeeperTestSuite) SetupTest() { encCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, mint.AppModule{}) key := storetypes.NewKVStoreKey(types.StoreKey) storeService := runtime.NewKVStoreService(key) @@ -67,31 +67,106 @@ func (s *IntegrationTestSuite) SetupTest() { s.bankKeeper = bankKeeper err := s.mintKeeper.Params.Set(s.ctx, types.DefaultParams()) - s.Require().NoError(err) + s.NoError(err) - s.Require().NoError(s.mintKeeper.Minter.Set(s.ctx, types.DefaultInitialMinter())) + s.NoError(s.mintKeeper.Minter.Set(s.ctx, types.DefaultInitialMinter())) s.msgServer = keeper.NewMsgServerImpl(s.mintKeeper) } -func (s *IntegrationTestSuite) TestAliasFunctions() { +func (s *KeeperTestSuite) TestAliasFunctions() { stakingTokenSupply := math.NewIntFromUint64(100000000000) s.stakingKeeper.EXPECT().StakingTokenSupply(s.ctx).Return(stakingTokenSupply, nil) tokenSupply, err := s.mintKeeper.StakingTokenSupply(s.ctx) - s.Require().NoError(err) - s.Require().Equal(tokenSupply, stakingTokenSupply) + s.NoError(err) + s.Equal(tokenSupply, stakingTokenSupply) bondedRatio := math.LegacyNewDecWithPrec(15, 2) s.stakingKeeper.EXPECT().BondedRatio(s.ctx).Return(bondedRatio, nil) ratio, err := s.mintKeeper.BondedRatio(s.ctx) - s.Require().NoError(err) - s.Require().Equal(ratio, bondedRatio) + s.NoError(err) + s.Equal(ratio, bondedRatio) coins := sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(1000000))) s.bankKeeper.EXPECT().MintCoins(s.ctx, types.ModuleName, coins).Return(nil) - s.Require().Equal(s.mintKeeper.MintCoins(s.ctx, sdk.NewCoins()), nil) - s.Require().Nil(s.mintKeeper.MintCoins(s.ctx, coins)) + s.Equal(s.mintKeeper.MintCoins(s.ctx, sdk.NewCoins()), nil) + s.Nil(s.mintKeeper.MintCoins(s.ctx, coins)) fees := sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(1000))) s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(s.ctx, types.ModuleName, authtypes.FeeCollectorName, fees).Return(nil) - s.Require().Nil(s.mintKeeper.AddCollectedFees(s.ctx, fees)) + s.Nil(s.mintKeeper.AddCollectedFees(s.ctx, fees)) +} + +func (s *KeeperTestSuite) TestDefaultMintFn() { + s.stakingKeeper.EXPECT().StakingTokenSupply(s.ctx).Return(math.NewIntFromUint64(100000000000), nil).AnyTimes() + bondedRatio := math.LegacyNewDecWithPrec(15, 2) + s.stakingKeeper.EXPECT().BondedRatio(s.ctx).Return(bondedRatio, nil).AnyTimes() + s.bankKeeper.EXPECT().MintCoins(s.ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(792)))).Return(nil) + s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(s.ctx, types.ModuleName, authtypes.FeeCollectorName, gomock.Any()).Return(nil) + + minter, err := s.mintKeeper.Minter.Get(s.ctx) + s.NoError(err) + + err = s.mintKeeper.DefaultMintFn(types.DefaultInflationCalculationFn)(s.ctx, s.mintKeeper.Environment, &minter, "block", 0) + s.NoError(err) + + // set a maxsupply and call again + params, err := s.mintKeeper.Params.Get(s.ctx) + s.NoError(err) + params.MaxSupply = math.NewInt(10000000000) + err = s.mintKeeper.Params.Set(s.ctx, params) + s.NoError(err) + + err = s.mintKeeper.DefaultMintFn(types.DefaultInflationCalculationFn)(s.ctx, s.mintKeeper.Environment, &minter, "block", 0) + s.NoError(err) + + // modify max supply to be almost reached + // we tried to mint 2059stake but we only get to mint 2000stake + params, err = s.mintKeeper.Params.Get(s.ctx) + s.NoError(err) + params.MaxSupply = math.NewInt(100000000000 + 2000) + err = s.mintKeeper.Params.Set(s.ctx, params) + s.NoError(err) + + s.bankKeeper.EXPECT().MintCoins(s.ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(792)))).Return(nil) + s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(s.ctx, types.ModuleName, authtypes.FeeCollectorName, gomock.Any()).Return(nil) + + err = s.mintKeeper.DefaultMintFn(types.DefaultInflationCalculationFn)(s.ctx, s.mintKeeper.Environment, &minter, "block", 0) + s.NoError(err) +} + +func (s *KeeperTestSuite) TestBeginBlocker() { + s.stakingKeeper.EXPECT().StakingTokenSupply(s.ctx).Return(math.NewIntFromUint64(100000000000), nil).AnyTimes() + bondedRatio := math.LegacyNewDecWithPrec(15, 2) + s.stakingKeeper.EXPECT().BondedRatio(s.ctx).Return(bondedRatio, nil).AnyTimes() + s.bankKeeper.EXPECT().MintCoins(s.ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(792)))).Return(nil) + s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(s.ctx, types.ModuleName, authtypes.FeeCollectorName, gomock.Any()).Return(nil) + + // get minter (it should get modified aftwerwards) + minter, err := s.mintKeeper.Minter.Get(s.ctx) + s.NoError(err) + + err = s.mintKeeper.BeginBlocker(s.ctx, s.mintKeeper.DefaultMintFn(types.DefaultInflationCalculationFn)) + s.NoError(err) + + // get minter again and compare + newMinter, err := s.mintKeeper.Minter.Get(s.ctx) + s.NoError(err) + s.NotEqual(minter, newMinter) +} + +func (s *KeeperTestSuite) TestMigrator() { + m := keeper.NewMigrator(s.mintKeeper) + s.NoError(m.Migrate1to2(s.ctx)) // just to get the coverage up + + // set max supply to one and migrate (should get it to zero) + params, err := s.mintKeeper.Params.Get(s.ctx) + s.NoError(err) + params.MaxSupply = math.OneInt() + s.NoError(s.mintKeeper.Params.Set(s.ctx, params)) + + s.NoError(m.Migrate2to3(s.ctx)) + + newParams, err := s.mintKeeper.Params.Get(s.ctx) + s.NoError(err) + s.Equal(math.ZeroInt(), newParams.MaxSupply) } diff --git a/x/mint/keeper/msg_server_test.go b/x/mint/keeper/msg_server_test.go index a999150207f0..10423e26e2c6 100644 --- a/x/mint/keeper/msg_server_test.go +++ b/x/mint/keeper/msg_server_test.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -func (s *IntegrationTestSuite) TestUpdateParams() { +func (s *KeeperTestSuite) TestUpdateParams() { testCases := []struct { name string request *types.MsgUpdateParams diff --git a/x/mint/module.go b/x/mint/module.go index 8c0d69bce55a..990f281edc4a 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -44,28 +44,31 @@ type AppModule struct { keeper keeper.Keeper authKeeper types.AccountKeeper - // inflationCalculator is used to calculate the inflation rate during BeginBlock. - // If inflationCalculator is nil, the default inflation calculation logic is used. - inflationCalculator types.InflationCalculationFn + // mintFn is used to mint new coins during BeginBlock. This function is in charge of + // minting new coins based on arbitrary logic, previously done through InflationCalculationFn. + // If mintFn is nil, the default minting logic is used. + mintFn types.MintFn } // NewAppModule creates a new AppModule object. -// If the InflationCalculationFn argument is nil, then the SDK's default inflation function will be used. +// If the mintFn argument is nil, then the SDK's default minting function will be used. func NewAppModule( cdc codec.Codec, keeper keeper.Keeper, ak types.AccountKeeper, - ic types.InflationCalculationFn, + mintFn types.MintFn, ) AppModule { - if ic == nil { - ic = types.DefaultInflationCalculationFn + // If mintFn is nil, use the default minting function. + // This check also happens in ProvideModule when used with depinject. + if mintFn == nil { + mintFn = keeper.DefaultMintFn(types.DefaultInflationCalculationFn) } return AppModule{ - cdc: cdc, - keeper: keeper, - authKeeper: ak, - inflationCalculator: ic, + cdc: cdc, + keeper: keeper, + authKeeper: ak, + mintFn: mintFn, } } @@ -157,7 +160,7 @@ func (AppModule) ConsensusVersion() uint64 { return ConsensusVersion } // BeginBlock returns the begin blocker for the mint module. func (am AppModule) BeginBlock(ctx context.Context) error { - return am.keeper.BeginBlocker(ctx, am.inflationCalculator) + return am.keeper.BeginBlocker(ctx, am.mintFn) } // AppModuleSimulation functions diff --git a/x/mint/module_test.go b/x/mint/module_test.go new file mode 100644 index 000000000000..9dc9e75e2ada --- /dev/null +++ b/x/mint/module_test.go @@ -0,0 +1,92 @@ +package mint_test + +import ( + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/suite" + + "cosmossdk.io/log" + "cosmossdk.io/math" + storetypes "cosmossdk.io/store/types" + authtypes "cosmossdk.io/x/auth/types" + "cosmossdk.io/x/mint" + "cosmossdk.io/x/mint/keeper" + minttestutil "cosmossdk.io/x/mint/testutil" + "cosmossdk.io/x/mint/types" + + codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" +) + +const govModuleNameStr = "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn" + +type ModuleTestSuite struct { + suite.Suite + + mintKeeper keeper.Keeper + ctx sdk.Context + msgServer types.MsgServer + stakingKeeper *minttestutil.MockStakingKeeper + bankKeeper *minttestutil.MockBankKeeper + + appmodule mint.AppModule +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(ModuleTestSuite)) +} + +func (s *ModuleTestSuite) SetupTest() { + encCfg := moduletestutil.MakeTestEncodingConfig(codectestutil.CodecOptions{}, mint.AppModule{}) + key := storetypes.NewKVStoreKey(types.StoreKey) + storeService := runtime.NewKVStoreService(key) + env := runtime.NewEnvironment(storeService, log.NewNopLogger()) + testCtx := testutil.DefaultContextWithDB(s.T(), key, storetypes.NewTransientStoreKey("transient_test")) + s.ctx = testCtx.Ctx + + // gomock initializations + ctrl := gomock.NewController(s.T()) + accountKeeper := minttestutil.NewMockAccountKeeper(ctrl) + bankKeeper := minttestutil.NewMockBankKeeper(ctrl) + stakingKeeper := minttestutil.NewMockStakingKeeper(ctrl) + + accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(sdk.AccAddress{}) + + s.mintKeeper = keeper.NewKeeper( + encCfg.Codec, + env, + stakingKeeper, + accountKeeper, + bankKeeper, + authtypes.FeeCollectorName, + govModuleNameStr, + ) + s.stakingKeeper = stakingKeeper + s.bankKeeper = bankKeeper + + err := s.mintKeeper.Params.Set(s.ctx, types.DefaultParams()) + s.NoError(err) + + s.NoError(s.mintKeeper.Minter.Set(s.ctx, types.DefaultInitialMinter())) + s.msgServer = keeper.NewMsgServerImpl(s.mintKeeper) + + s.appmodule = mint.NewAppModule(encCfg.Codec, s.mintKeeper, accountKeeper, s.mintKeeper.DefaultMintFn(types.DefaultInflationCalculationFn)) +} + +func (s *ModuleTestSuite) TestEpochHooks() { + s.stakingKeeper.EXPECT().StakingTokenSupply(s.ctx).Return(math.NewIntFromUint64(100000000000), nil).AnyTimes() + bondedRatio := math.LegacyNewDecWithPrec(15, 2) + s.stakingKeeper.EXPECT().BondedRatio(s.ctx).Return(bondedRatio, nil).AnyTimes() + s.bankKeeper.EXPECT().MintCoins(s.ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(792)))).Return(nil) + s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(s.ctx, types.ModuleName, authtypes.FeeCollectorName, gomock.Any()).Return(nil) + + err := s.appmodule.BeforeEpochStart(s.ctx, "block", -1) + s.NoError(err) + + err = s.appmodule.AfterEpochEnd(s.ctx, "epochIdentifier", 1) // just to get coverage up + s.NoError(err) +} diff --git a/x/mint/proto/cosmos/mint/v1beta1/mint.proto b/x/mint/proto/cosmos/mint/v1beta1/mint.proto index da2bfcbc8db6..d7b577ec617c 100644 --- a/x/mint/proto/cosmos/mint/v1beta1/mint.proto +++ b/x/mint/proto/cosmos/mint/v1beta1/mint.proto @@ -6,6 +6,7 @@ option go_package = "cosmossdk.io/x/mint/types"; import "gogoproto/gogo.proto"; import "cosmos_proto/cosmos.proto"; import "amino/amino.proto"; +import "google/protobuf/any.proto"; // Minter represents the minting state. message Minter { @@ -21,6 +22,10 @@ message Minter { (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", (gogoproto.nullable) = false ]; + + // data is any custom data that the user might want to put in the minter, to + // be used in the minting process. + bytes data = 3; } // Params defines the parameters for the x/mint module. diff --git a/x/mint/types/genesis.go b/x/mint/types/genesis.go index 6ed2f38a18ec..44e77bb4cc4c 100644 --- a/x/mint/types/genesis.go +++ b/x/mint/types/genesis.go @@ -3,6 +3,7 @@ package types import ( "context" + "cosmossdk.io/core/appmodule" "cosmossdk.io/math" ) @@ -11,9 +12,14 @@ import ( // bondedRatio and returns the newly calculated inflation rate. // It can be used to specify a custom inflation calculation logic, instead of relying on the // default logic provided by the sdk. +// Deprecated: use MintFn instead. type InflationCalculationFn func(ctx context.Context, minter Minter, params Params, bondedRatio math.LegacyDec) math.LegacyDec +// MintFn defines the function that needs to be implemented in order to customize the minting process. +type MintFn func(ctx context.Context, env appmodule.Environment, minter *Minter, epochId string, epochNumber int64) error + // DefaultInflationCalculationFn is the default function used to calculate inflation. +// Deprecated: use DefaultMintFn instead. func DefaultInflationCalculationFn(_ context.Context, minter Minter, params Params, bondedRatio math.LegacyDec) math.LegacyDec { return minter.NextInflationRate(params, bondedRatio) } diff --git a/x/mint/types/genesis_test.go b/x/mint/types/genesis_test.go new file mode 100644 index 000000000000..950c2ca43432 --- /dev/null +++ b/x/mint/types/genesis_test.go @@ -0,0 +1,21 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGenesis(t *testing.T) { + minter := DefaultInitialMinter() + params := DefaultParams() + + gs := NewGenesisState(minter, params) + err := ValidateGenesis(*gs) + require.NoError(t, err) + + defaultGs := DefaultGenesisState() + err = ValidateGenesis(*defaultGs) + require.NoError(t, err) + require.Equal(t, gs, defaultGs) +} diff --git a/x/mint/types/mint.pb.go b/x/mint/types/mint.pb.go index 7ce197d326ab..35cd40591a27 100644 --- a/x/mint/types/mint.pb.go +++ b/x/mint/types/mint.pb.go @@ -10,6 +10,7 @@ import ( _ "github.com/cosmos/cosmos-sdk/types/tx/amino" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" + _ "github.com/cosmos/gogoproto/types/any" io "io" math "math" math_bits "math/bits" @@ -32,6 +33,9 @@ type Minter struct { Inflation cosmossdk_io_math.LegacyDec `protobuf:"bytes,1,opt,name=inflation,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"inflation"` // current annual expected provisions AnnualProvisions cosmossdk_io_math.LegacyDec `protobuf:"bytes,2,opt,name=annual_provisions,json=annualProvisions,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"annual_provisions"` + // data is any custom data that the user might want to put in the minter, to + // be used in the minting process. + Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` } func (m *Minter) Reset() { *m = Minter{} } @@ -67,6 +71,13 @@ func (m *Minter) XXX_DiscardUnknown() { var xxx_messageInfo_Minter proto.InternalMessageInfo +func (m *Minter) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + // Params defines the parameters for the x/mint module. type Params struct { // type of coin to mint @@ -140,36 +151,38 @@ func init() { func init() { proto.RegisterFile("cosmos/mint/v1beta1/mint.proto", fileDescriptor_2df116d183c1e223) } var fileDescriptor_2df116d183c1e223 = []byte{ - // 461 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0x4f, 0x6b, 0xd4, 0x40, - 0x18, 0xc6, 0x37, 0xba, 0xae, 0xec, 0x68, 0xd1, 0x4e, 0x2d, 0x4c, 0x2b, 0x4d, 0x4b, 0x0f, 0x52, - 0x2a, 0xdd, 0xb0, 0x14, 0x3c, 0x78, 0x5c, 0xf7, 0x52, 0xb1, 0xb8, 0xc4, 0x83, 0xa8, 0xe0, 0xf0, - 0x6e, 0x32, 0xa6, 0xe3, 0x66, 0x66, 0xc2, 0xcc, 0xb4, 0x64, 0xbf, 0x82, 0x27, 0x3f, 0x86, 0xc7, - 0x1e, 0xbc, 0xf4, 0x1b, 0xf4, 0x58, 0x3c, 0x89, 0x87, 0x22, 0xbb, 0x87, 0x7e, 0x0d, 0xc9, 0x4c, - 0x48, 0xfd, 0x73, 0xd2, 0x7a, 0x09, 0xc9, 0xf3, 0xcc, 0xfb, 0x7b, 0x1e, 0xc2, 0xbc, 0x28, 0x4c, - 0x94, 0x11, 0xca, 0x44, 0x82, 0x4b, 0x1b, 0x1d, 0xf5, 0xc7, 0xcc, 0x42, 0xdf, 0x7d, 0xf4, 0x0a, - 0xad, 0xac, 0xc2, 0x4b, 0xde, 0xef, 0x39, 0xa9, 0xf6, 0x57, 0xef, 0x65, 0x2a, 0x53, 0xce, 0x8f, - 0xaa, 0x37, 0x7f, 0x74, 0x75, 0xc5, 0x1f, 0xa5, 0xde, 0xa8, 0xe7, 0xbc, 0xb5, 0x08, 0x82, 0x4b, - 0x15, 0xb9, 0xa7, 0x97, 0x36, 0x4f, 0x02, 0xd4, 0xd9, 0xe7, 0xd2, 0x32, 0x8d, 0x9f, 0xa3, 0x2e, - 0x97, 0xef, 0x72, 0xb0, 0x5c, 0x49, 0x12, 0x6c, 0x04, 0x5b, 0xdd, 0x41, 0xff, 0xf4, 0x7c, 0xbd, - 0xf5, 0xed, 0x7c, 0xfd, 0xbe, 0xc7, 0x98, 0x74, 0xd2, 0xe3, 0x2a, 0x12, 0x60, 0x0f, 0x7a, 0xcf, - 0x58, 0x06, 0xc9, 0x74, 0xc8, 0x92, 0x2f, 0x9f, 0x77, 0x50, 0x9d, 0x32, 0x64, 0x49, 0x7c, 0xc9, - 0xc0, 0x6f, 0xd1, 0x22, 0x48, 0x79, 0x08, 0x79, 0xd5, 0xe5, 0x88, 0x1b, 0xae, 0xa4, 0x21, 0xd7, - 0xfe, 0x15, 0x7c, 0xd7, 0xb3, 0x46, 0x0d, 0x6a, 0xf3, 0xa4, 0x8d, 0x3a, 0x23, 0xd0, 0x20, 0x0c, - 0x5e, 0x43, 0xa8, 0xfa, 0x35, 0x34, 0x65, 0x52, 0x09, 0x5f, 0x3e, 0xee, 0x56, 0xca, 0xb0, 0x12, - 0xf0, 0x7b, 0xb4, 0xdc, 0xd4, 0xa2, 0x1a, 0x2c, 0xa3, 0xc9, 0x01, 0xc8, 0x8c, 0xd5, 0x6d, 0x1e, - 0xfd, 0x75, 0x9b, 0x4f, 0x17, 0xc7, 0xdb, 0x41, 0xbc, 0xd4, 0x40, 0x63, 0xb0, 0xec, 0x89, 0x43, - 0xe2, 0x37, 0x68, 0xe1, 0x32, 0x4b, 0x40, 0x49, 0xae, 0x5f, 0x29, 0xe3, 0x76, 0x03, 0xdb, 0x87, - 0xf2, 0x37, 0x38, 0x97, 0xa4, 0xfd, 0xbf, 0xe0, 0x5c, 0xe2, 0x97, 0xe8, 0x56, 0xa6, 0x20, 0xa7, - 0x63, 0x25, 0x53, 0x96, 0x92, 0x1b, 0x57, 0x42, 0xa3, 0x0a, 0x35, 0x70, 0x24, 0xfc, 0x00, 0xdd, - 0x19, 0xe7, 0x2a, 0x99, 0x18, 0x5a, 0x30, 0x4d, 0xa7, 0x0c, 0x34, 0xe9, 0x6c, 0x04, 0x5b, 0xed, - 0x78, 0xc1, 0xcb, 0x23, 0xa6, 0x5f, 0x31, 0xd0, 0xf8, 0x29, 0x42, 0x02, 0x4a, 0x6a, 0x0e, 0x8b, - 0x22, 0x9f, 0x92, 0x9b, 0x2e, 0xff, 0x61, 0x9d, 0xbf, 0xfc, 0x67, 0xfe, 0x9e, 0xb4, 0x3f, 0x25, - 0xef, 0x49, 0x1b, 0x77, 0x05, 0x94, 0x2f, 0xdc, 0xf4, 0xe3, 0xb5, 0x0f, 0x17, 0xc7, 0xdb, 0xc4, - 0x7b, 0x3b, 0x26, 0x9d, 0x44, 0xa5, 0x5f, 0x2e, 0x7f, 0x61, 0x06, 0xbb, 0xa7, 0xb3, 0x30, 0x38, - 0x9b, 0x85, 0xc1, 0xf7, 0x59, 0x18, 0x7c, 0x9c, 0x87, 0xad, 0xb3, 0x79, 0xd8, 0xfa, 0x3a, 0x0f, - 0x5b, 0xaf, 0x57, 0x7e, 0x09, 0xaa, 0xa7, 0xec, 0xb4, 0x60, 0x66, 0xdc, 0x71, 0x3b, 0xb3, 0xfb, - 0x23, 0x00, 0x00, 0xff, 0xff, 0x5e, 0xda, 0x10, 0x60, 0xae, 0x03, 0x00, 0x00, + // 490 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0x3f, 0x6f, 0xd3, 0x40, + 0x18, 0xc6, 0x73, 0x10, 0x82, 0x72, 0xb4, 0x82, 0x5e, 0xa9, 0xe4, 0x16, 0xd5, 0x8d, 0x3a, 0xa0, + 0xa8, 0xa8, 0xb1, 0xa2, 0x4a, 0x0c, 0x8c, 0x21, 0x4b, 0x11, 0x15, 0x91, 0x19, 0x10, 0x20, 0x61, + 0xbd, 0xb6, 0xaf, 0xee, 0x11, 0xdf, 0x9d, 0xe5, 0xbb, 0x54, 0xf6, 0x57, 0x60, 0xe2, 0x63, 0x30, + 0x76, 0x60, 0xe1, 0x1b, 0x74, 0x41, 0xaa, 0x98, 0x10, 0x43, 0x85, 0x92, 0xa1, 0x5f, 0x03, 0xf9, + 0xce, 0xa4, 0xfc, 0x99, 0x08, 0x5d, 0xac, 0xbb, 0xf7, 0x79, 0xdf, 0xdf, 0xf3, 0xd8, 0xf2, 0x8b, + 0xdd, 0x48, 0x2a, 0x2e, 0x95, 0xc7, 0x99, 0xd0, 0xde, 0x71, 0x3f, 0xa4, 0x1a, 0xfa, 0xe6, 0xd2, + 0xcb, 0x72, 0xa9, 0x25, 0x59, 0xb5, 0x7a, 0xcf, 0x94, 0x6a, 0x7d, 0xe3, 0x6e, 0x22, 0x13, 0x69, + 0x74, 0xaf, 0x3a, 0xd9, 0xd6, 0x8d, 0x75, 0xdb, 0x1a, 0x58, 0xa1, 0x9e, 0xb3, 0xd2, 0x0a, 0x70, + 0x26, 0xa4, 0x67, 0x9e, 0x3f, 0xbb, 0x13, 0x29, 0x93, 0x94, 0x7a, 0xe6, 0x16, 0x4e, 0x0e, 0x3d, + 0x10, 0xa5, 0x95, 0xb6, 0x3f, 0x23, 0xdc, 0x3a, 0x60, 0x42, 0xd3, 0x9c, 0x3c, 0xc3, 0x6d, 0x26, + 0x0e, 0x53, 0xd0, 0x4c, 0x0a, 0x07, 0x75, 0x50, 0xb7, 0x3d, 0xe8, 0x9f, 0x9e, 0x6f, 0x35, 0xbe, + 0x9d, 0x6f, 0xdd, 0xb3, 0x0e, 0x2a, 0x1e, 0xf7, 0x98, 0xf4, 0x38, 0xe8, 0xa3, 0xde, 0x53, 0x9a, + 0x40, 0x54, 0x0e, 0x69, 0xf4, 0xe5, 0xe3, 0x2e, 0xae, 0x03, 0x0c, 0x69, 0xe4, 0x5f, 0x32, 0xc8, + 0x1b, 0xbc, 0x02, 0x42, 0x4c, 0x20, 0xad, 0x62, 0x1e, 0x33, 0xc5, 0xa4, 0x50, 0xce, 0xb5, 0x45, + 0xc1, 0x77, 0x2c, 0x6b, 0x34, 0x47, 0x11, 0x82, 0x9b, 0x31, 0x68, 0x70, 0xae, 0x77, 0x50, 0x77, + 0xc9, 0x37, 0xe7, 0xed, 0x4f, 0x4d, 0xdc, 0x1a, 0x41, 0x0e, 0x5c, 0x91, 0x4d, 0x8c, 0xab, 0x2f, + 0x19, 0xc4, 0x54, 0x48, 0x6e, 0x5f, 0xc8, 0x6f, 0x57, 0x95, 0x61, 0x55, 0x20, 0x6f, 0xf1, 0xda, + 0x3c, 0x6a, 0x90, 0x83, 0xa6, 0x41, 0x74, 0x04, 0x22, 0xa1, 0x75, 0xc2, 0x87, 0xff, 0x9c, 0xf0, + 0xc3, 0xc5, 0xc9, 0x0e, 0xf2, 0x57, 0xe7, 0x50, 0x1f, 0x34, 0x7d, 0x6c, 0x90, 0xe4, 0x35, 0x5e, + 0xbe, 0xf4, 0xe2, 0x50, 0x98, 0xc8, 0x8b, 0x7b, 0x2c, 0xcd, 0x61, 0x07, 0x50, 0xfc, 0x01, 0x67, + 0xc2, 0x69, 0x5e, 0x15, 0x9c, 0x09, 0xf2, 0x02, 0xdf, 0x4a, 0x24, 0xa4, 0x41, 0x28, 0x45, 0x4c, + 0x63, 0xe7, 0xc6, 0x7f, 0xa1, 0x71, 0x85, 0x1a, 0x18, 0x12, 0xb9, 0x8f, 0x6f, 0x87, 0xa9, 0x8c, + 0xc6, 0x2a, 0xc8, 0x68, 0x1e, 0x94, 0x14, 0x72, 0xa7, 0xd5, 0x41, 0xdd, 0xa6, 0xbf, 0x6c, 0xcb, + 0x23, 0x9a, 0xbf, 0xa4, 0x90, 0x93, 0x27, 0x18, 0x73, 0x28, 0x02, 0x35, 0xc9, 0xb2, 0xb4, 0x74, + 0x6e, 0x1a, 0xff, 0x07, 0xb5, 0xff, 0xda, 0xdf, 0xfe, 0xfb, 0x42, 0xff, 0xe2, 0xbc, 0x2f, 0xb4, + 0xdf, 0xe6, 0x50, 0x3c, 0x37, 0xd3, 0x8f, 0x36, 0xdf, 0x5d, 0x9c, 0xec, 0x38, 0x56, 0xdb, 0x55, + 0xf1, 0xd8, 0x2b, 0xec, 0x2e, 0xda, 0x1f, 0x66, 0xb0, 0x77, 0x3a, 0x75, 0xd1, 0xd9, 0xd4, 0x45, + 0xdf, 0xa7, 0x2e, 0x7a, 0x3f, 0x73, 0x1b, 0x67, 0x33, 0xb7, 0xf1, 0x75, 0xe6, 0x36, 0x5e, 0xad, + 0xff, 0x66, 0x54, 0x4f, 0xe9, 0x32, 0xa3, 0x2a, 0x6c, 0x99, 0x3d, 0xda, 0xfb, 0x11, 0x00, 0x00, + 0xff, 0xff, 0x53, 0x44, 0x4d, 0x1a, 0xdd, 0x03, 0x00, 0x00, } func (m *Minter) Marshal() (dAtA []byte, err error) { @@ -192,6 +205,13 @@ func (m *Minter) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintMint(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x1a + } { size := m.AnnualProvisions.Size() i -= size @@ -321,6 +341,10 @@ func (m *Minter) Size() (n int) { n += 1 + l + sovMint(uint64(l)) l = m.AnnualProvisions.Size() n += 1 + l + sovMint(uint64(l)) + l = len(m.Data) + if l > 0 { + n += 1 + l + sovMint(uint64(l)) + } return n } @@ -453,6 +477,40 @@ func (m *Minter) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthMint + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthMint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipMint(dAtA[iNdEx:]) diff --git a/x/mint/types/minter_test.go b/x/mint/types/minter_test.go index b89773a6cb29..8bff2334995a 100644 --- a/x/mint/types/minter_test.go +++ b/x/mint/types/minter_test.go @@ -55,6 +55,9 @@ func TestNextInflation(t *testing.T) { inflation := minter.NextInflationRate(params, tc.bondedRatio) diffInflation := inflation.Sub(tc.setInflation) + annualProvisions := minter.NextAnnualProvisions(params, math.NewInt(100000000000000)) + require.Equal(t, minter.Inflation.MulInt(math.NewInt(100000000000000)), annualProvisions) + require.True(t, diffInflation.Equal(tc.expChange), "Test Index: %v\nDiff: %v\nExpected: %v\n", i, diffInflation, tc.expChange) } @@ -88,6 +91,25 @@ func TestBlockProvision(t *testing.T) { } } +func TestValidateMinter(t *testing.T) { + tests := []struct { + minter Minter + expErr bool + }{ + {InitialMinter(math.LegacyNewDecWithPrec(1, 1)), false}, + {InitialMinter(math.LegacyNewDecWithPrec(-1, 1)), true}, + {InitialMinter(math.LegacyZeroDec()), false}, + } + for i, tc := range tests { + err := ValidateMinter(tc.minter) + if tc.expErr { + require.Error(t, err, "test: %v", i) + } else { + require.NoError(t, err, "test: %v", i) + } + } +} + // Benchmarking :) // previously using math.Int operations: // BenchmarkBlockProvision-4 5000000 220 ns/op diff --git a/x/mint/types/params.go b/x/mint/types/params.go index 370eeea9106e..dfc00348b3db 100644 --- a/x/mint/types/params.go +++ b/x/mint/types/params.go @@ -69,12 +69,7 @@ func (p Params) Validate() error { return nil } -func validateMintDenom(i interface{}) error { - v, ok := i.(string) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - +func validateMintDenom(v string) error { if strings.TrimSpace(v) == "" { return errors.New("mint denom cannot be blank") } @@ -85,12 +80,7 @@ func validateMintDenom(i interface{}) error { return nil } -func validateInflationRateChange(i interface{}) error { - v, ok := i.(math.LegacyDec) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - +func validateInflationRateChange(v math.LegacyDec) error { if v.IsNil() { return fmt.Errorf("inflation rate change cannot be nil: %s", v) } @@ -104,12 +94,7 @@ func validateInflationRateChange(i interface{}) error { return nil } -func validateInflationMax(i interface{}) error { - v, ok := i.(math.LegacyDec) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - +func validateInflationMax(v math.LegacyDec) error { if v.IsNil() { return fmt.Errorf("max inflation cannot be nil: %s", v) } @@ -123,12 +108,7 @@ func validateInflationMax(i interface{}) error { return nil } -func validateInflationMin(i interface{}) error { - v, ok := i.(math.LegacyDec) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - +func validateInflationMin(v math.LegacyDec) error { if v.IsNil() { return fmt.Errorf("min inflation cannot be nil: %s", v) } @@ -142,12 +122,7 @@ func validateInflationMin(i interface{}) error { return nil } -func validateGoalBonded(i interface{}) error { - v, ok := i.(math.LegacyDec) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - +func validateGoalBonded(v math.LegacyDec) error { if v.IsNil() { return fmt.Errorf("goal bonded cannot be nil: %s", v) } @@ -161,12 +136,7 @@ func validateGoalBonded(i interface{}) error { return nil } -func validateBlocksPerYear(i interface{}) error { - v, ok := i.(uint64) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - +func validateBlocksPerYear(v uint64) error { if v == 0 { return fmt.Errorf("blocks per year must be positive: %d", v) } @@ -174,12 +144,7 @@ func validateBlocksPerYear(i interface{}) error { return nil } -func validateMaxSupply(i interface{}) error { - v, ok := i.(math.Int) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - +func validateMaxSupply(v math.Int) error { if v.IsNegative() { return fmt.Errorf("max supply must be positive: %d", v) } diff --git a/x/mint/types/params_test.go b/x/mint/types/params_test.go new file mode 100644 index 000000000000..b43c6212d058 --- /dev/null +++ b/x/mint/types/params_test.go @@ -0,0 +1,112 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "cosmossdk.io/math" +) + +func TestValidate(t *testing.T) { + params := DefaultParams() + err := params.Validate() + require.NoError(t, err) + + params2 := NewParams( + params.MintDenom, + params.InflationRateChange, + params.InflationMax, + params.InflationMin, + params.GoalBonded, + params.BlocksPerYear, + params.MaxSupply, + ) + err = params2.Validate() + require.NoError(t, err) + require.Equal(t, params, params2) + + params.MintDenom = "" + err = params.Validate() + require.Error(t, err) + + params.MintDenom = "asd/$%!@#" + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.InflationRateChange = math.LegacyNewDec(123) + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.InflationRateChange = math.LegacyNewDec(-123) + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.InflationRateChange = math.LegacyDec{} + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.InflationMax = math.LegacyNewDec(123) + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.InflationMax = math.LegacyNewDec(-123) + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.InflationMax = math.LegacyDec{} + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.InflationMin = math.LegacyNewDec(123) + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.InflationMin = math.LegacyNewDec(-123) + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.InflationMin = math.LegacyDec{} + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.GoalBonded = math.LegacyNewDec(123) + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.GoalBonded = math.LegacyNewDec(-123) + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.GoalBonded = math.LegacyDec{} + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.BlocksPerYear = 0 + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.MaxSupply = math.NewInt(-1) + err = params.Validate() + require.Error(t, err) + + params = DefaultParams() + params.InflationMax = math.LegacyNewDecWithPrec(1, 2) + params.InflationMin = math.LegacyNewDecWithPrec(2, 2) + err = params.Validate() + require.Error(t, err) +}