diff --git a/api/poktroll/supplier/params.pulsar.go b/api/poktroll/supplier/params.pulsar.go index bb3c96973..9048f64d1 100644 --- a/api/poktroll/supplier/params.pulsar.go +++ b/api/poktroll/supplier/params.pulsar.go @@ -16,14 +16,16 @@ import ( ) var ( - md_Params protoreflect.MessageDescriptor - fd_Params_min_stake protoreflect.FieldDescriptor + md_Params protoreflect.MessageDescriptor + fd_Params_min_stake protoreflect.FieldDescriptor + fd_Params_staking_fee protoreflect.FieldDescriptor ) func init() { file_poktroll_supplier_params_proto_init() md_Params = File_poktroll_supplier_params_proto.Messages().ByName("Params") fd_Params_min_stake = md_Params.Fields().ByName("min_stake") + fd_Params_staking_fee = md_Params.Fields().ByName("staking_fee") } var _ protoreflect.Message = (*fastReflection_Params)(nil) @@ -97,6 +99,12 @@ func (x *fastReflection_Params) Range(f func(protoreflect.FieldDescriptor, proto return } } + if x.StakingFee != nil { + value := protoreflect.ValueOfMessage(x.StakingFee.ProtoReflect()) + if !f(fd_Params_staking_fee, value) { + return + } + } } // Has reports whether a field is populated. @@ -114,6 +122,8 @@ func (x *fastReflection_Params) Has(fd protoreflect.FieldDescriptor) bool { switch fd.FullName() { case "poktroll.supplier.Params.min_stake": return x.MinStake != nil + case "poktroll.supplier.Params.staking_fee": + return x.StakingFee != nil default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -132,6 +142,8 @@ func (x *fastReflection_Params) Clear(fd protoreflect.FieldDescriptor) { switch fd.FullName() { case "poktroll.supplier.Params.min_stake": x.MinStake = nil + case "poktroll.supplier.Params.staking_fee": + x.StakingFee = nil default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -151,6 +163,9 @@ func (x *fastReflection_Params) Get(descriptor protoreflect.FieldDescriptor) pro case "poktroll.supplier.Params.min_stake": value := x.MinStake return protoreflect.ValueOfMessage(value.ProtoReflect()) + case "poktroll.supplier.Params.staking_fee": + value := x.StakingFee + return protoreflect.ValueOfMessage(value.ProtoReflect()) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -173,6 +188,8 @@ func (x *fastReflection_Params) Set(fd protoreflect.FieldDescriptor, value proto switch fd.FullName() { case "poktroll.supplier.Params.min_stake": x.MinStake = value.Message().Interface().(*v1beta1.Coin) + case "poktroll.supplier.Params.staking_fee": + x.StakingFee = value.Message().Interface().(*v1beta1.Coin) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -198,6 +215,11 @@ func (x *fastReflection_Params) Mutable(fd protoreflect.FieldDescriptor) protore x.MinStake = new(v1beta1.Coin) } return protoreflect.ValueOfMessage(x.MinStake.ProtoReflect()) + case "poktroll.supplier.Params.staking_fee": + if x.StakingFee == nil { + x.StakingFee = new(v1beta1.Coin) + } + return protoreflect.ValueOfMessage(x.StakingFee.ProtoReflect()) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -214,6 +236,9 @@ func (x *fastReflection_Params) NewField(fd protoreflect.FieldDescriptor) protor case "poktroll.supplier.Params.min_stake": m := new(v1beta1.Coin) return protoreflect.ValueOfMessage(m.ProtoReflect()) + case "poktroll.supplier.Params.staking_fee": + m := new(v1beta1.Coin) + return protoreflect.ValueOfMessage(m.ProtoReflect()) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.supplier.Params")) @@ -287,6 +312,10 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { l = options.Size(x.MinStake) n += 1 + l + runtime.Sov(uint64(l)) } + if x.StakingFee != nil { + l = options.Size(x.StakingFee) + n += 1 + l + runtime.Sov(uint64(l)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -316,6 +345,20 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if x.StakingFee != nil { + encoded, err := options.Marshal(x.StakingFee) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + } if x.MinStake != nil { encoded, err := options.Marshal(x.MinStake) if err != nil { @@ -415,6 +458,42 @@ func (x *fastReflection_Params) ProtoMethods() *protoiface.Methods { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err } iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field StakingFee", wireType) + } + var msglen 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++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + 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 + } + if x.StakingFee == nil { + x.StakingFee = &v1beta1.Coin{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.StakingFee); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -472,6 +551,8 @@ type Params struct { // min_stake is the minimum amount of uPOKT that a supplier must stake to be // included in network sessions and remain staked. MinStake *v1beta1.Coin `protobuf:"bytes,1,opt,name=min_stake,json=minStake,proto3" json:"min_stake,omitempty"` + // staking_fee is the fee charged by the protocol for staking a supplier. + StakingFee *v1beta1.Coin `protobuf:"bytes,2,opt,name=staking_fee,json=stakingFee,proto3" json:"staking_fee,omitempty"` } func (x *Params) Reset() { @@ -501,6 +582,13 @@ func (x *Params) GetMinStake() *v1beta1.Coin { return nil } +func (x *Params) GetStakingFee() *v1beta1.Coin { + if x != nil { + return x.StakingFee + } + return nil +} + var File_poktroll_supplier_params_proto protoreflect.FileDescriptor var file_poktroll_supplier_params_proto_rawDesc = []byte{ @@ -511,28 +599,34 @@ var file_poktroll_supplier_params_proto_rawDesc = []byte{ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x88, 0x01, 0x0a, + 0x31, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xeb, 0x01, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x59, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x42, 0x21, 0xea, 0xde, 0x1f, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0xf2, 0xde, 0x1f, 0x10, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x22, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x53, 0x74, 0x61, - 0x6b, 0x65, 0x3a, 0x23, 0xe8, 0xa0, 0x1f, 0x01, 0x8a, 0xe7, 0xb0, 0x2a, 0x1a, 0x70, 0x6f, 0x6b, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x78, 0x2f, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, - 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xb1, 0x01, 0xd8, 0xe2, 0x1e, 0x01, 0x0a, 0x15, - 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x73, 0x75, 0x70, - 0x70, 0x6c, 0x69, 0x65, 0x72, 0x42, 0x0b, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x22, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, - 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, - 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0xa2, 0x02, 0x03, 0x50, 0x53, 0x58, 0xaa, 0x02, - 0x11, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, - 0x65, 0x72, 0xca, 0x02, 0x11, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x53, 0x75, - 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0xe2, 0x02, 0x1d, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, - 0x6c, 0x5c, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x12, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, - 0x6c, 0x3a, 0x3a, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x6b, 0x65, 0x12, 0x61, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x65, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, + 0x69, 0x6e, 0x42, 0x25, 0xea, 0xde, 0x1f, 0x0b, 0x73, 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x5f, + 0x66, 0x65, 0x65, 0xf2, 0xde, 0x1f, 0x12, 0x79, 0x61, 0x6d, 0x6c, 0x3a, 0x22, 0x73, 0x74, 0x61, + 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x65, 0x65, 0x22, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x6b, 0x69, + 0x6e, 0x67, 0x46, 0x65, 0x65, 0x3a, 0x23, 0xe8, 0xa0, 0x1f, 0x01, 0x8a, 0xe7, 0xb0, 0x2a, 0x1a, + 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x78, 0x2f, 0x73, 0x75, 0x70, 0x70, 0x6c, + 0x69, 0x65, 0x72, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xb1, 0x01, 0xd8, 0xe2, 0x1e, + 0x01, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, + 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x42, 0x0b, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x22, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, + 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x2f, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0xa2, 0x02, 0x03, 0x50, 0x53, + 0x58, 0xaa, 0x02, 0x11, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x53, 0x75, 0x70, + 0x70, 0x6c, 0x69, 0x65, 0x72, 0xca, 0x02, 0x11, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x5c, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0xe2, 0x02, 0x1d, 0x50, 0x6f, 0x6b, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5c, 0x47, 0x50, + 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x12, 0x50, 0x6f, 0x6b, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -554,11 +648,12 @@ var file_poktroll_supplier_params_proto_goTypes = []interface{}{ } var file_poktroll_supplier_params_proto_depIdxs = []int32{ 1, // 0: poktroll.supplier.Params.min_stake:type_name -> cosmos.base.v1beta1.Coin - 1, // [1:1] is the sub-list for method output_type - 1, // [1:1] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 1, // 1: poktroll.supplier.Params.staking_fee:type_name -> cosmos.base.v1beta1.Coin + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_poktroll_supplier_params_proto_init() } diff --git a/config.yml b/config.yml index f6bec72d1..ccde339a4 100644 --- a/config.yml +++ b/config.yml @@ -200,6 +200,10 @@ genesis: min_stake: amount: "1000000" # 1 POKT denom: upokt + # TODO_BETA(@bryanchriswhite): Determine realistic amount for supplier staking fee. + staking_fee: + amount: "1" # 1 uPOKT + denom: upokt supplierList: - owner_address: pokt19a3t4yunp0dlpfjrp7qwnzwlrzd5fzs2gjaaaj operator_address: pokt19a3t4yunp0dlpfjrp7qwnzwlrzd5fzs2gjaaaj diff --git a/makefiles/params.mk b/makefiles/params.mk index bbe99698a..a2968c102 100644 --- a/makefiles/params.mk +++ b/makefiles/params.mk @@ -148,6 +148,10 @@ params_update_supplier_all: ## Update the supplier module params params_update_supplier_min_stake: ## Update the supplier module min_stake param poktrolld tx authz exec ./tools/scripts/params/supplier_min_stake.json $(PARAM_FLAGS) +.PHONY: params_update_supplier_staking_fee +params_update_supplier_staking_fee: ## Update the supplier module staking_fee param + poktrolld tx authz exec ./tools/scripts/params/supplier_staking_fee.json $(PARAM_FLAGS) + ### Session Module Params ### .PHONY: params_get_session params_get_session: ## Get the session module params diff --git a/proto/poktroll/supplier/params.proto b/proto/poktroll/supplier/params.proto index d4e8c77ec..06fa9b7bc 100644 --- a/proto/poktroll/supplier/params.proto +++ b/proto/poktroll/supplier/params.proto @@ -16,4 +16,7 @@ message Params { // min_stake is the minimum amount of uPOKT that a supplier must stake to be // included in network sessions and remain staked. cosmos.base.v1beta1.Coin min_stake = 1 [(gogoproto.jsontag) = "min_stake", (gogoproto.moretags) = "yaml:\"min_stake\""]; + + // staking_fee is the fee charged by the protocol for staking a supplier. + cosmos.base.v1beta1.Coin staking_fee = 2 [(gogoproto.jsontag) = "staking_fee", (gogoproto.moretags) = "yaml:\"staking_fee\""]; } diff --git a/testutil/integration/suites/param_configs.go b/testutil/integration/suites/param_configs.go index 1e3a52e9e..d95a3050e 100644 --- a/testutil/integration/suites/param_configs.go +++ b/testutil/integration/suites/param_configs.go @@ -1,8 +1,6 @@ package suites import ( - "encoding/hex" - cosmostypes "github.com/cosmos/cosmos-sdk/types" "github.com/pokt-network/poktroll/app/volatile" @@ -70,8 +68,8 @@ var ( ValidProofMissingPenaltyCoin = cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 500) ValidProofSubmissionFeeCoin = cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 5000000) ValidProofRequirementThresholdCoin = cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 100) - ValidRelayDifficultyTargetHash, _ = hex.DecodeString("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff") ValidActorMinStake = cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 100) + ValidStakingFee = cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 1) SharedModuleParamConfig = ModuleParamConfig{ ParamsMsgs: ModuleParamsMessages{ @@ -192,7 +190,8 @@ var ( QueryParamsResponse: suppliertypes.QueryParamsResponse{}, }, ValidParams: suppliertypes.Params{ - MinStake: &ValidActorMinStake, + MinStake: &ValidActorMinStake, + StakingFee: &ValidStakingFee, }, ParamTypes: map[ParamType]any{ ParamTypeCoin: suppliertypes.MsgUpdateParam_AsCoin{}, diff --git a/tools/scripts/params/supplier_all.json b/tools/scripts/params/supplier_all.json index cded3172f..01d632f4c 100644 --- a/tools/scripts/params/supplier_all.json +++ b/tools/scripts/params/supplier_all.json @@ -8,6 +8,10 @@ "min_stake": { "amount": "1000000", "denom": "upokt" + }, + "staking_fee": { + "amount": "1", + "denom": "upokt" } } } diff --git a/tools/scripts/params/supplier_staking_fee.json b/tools/scripts/params/supplier_staking_fee.json new file mode 100644 index 000000000..baad22561 --- /dev/null +++ b/tools/scripts/params/supplier_staking_fee.json @@ -0,0 +1,15 @@ +{ + "body": { + "messages": [ + { + "@type": "/poktroll.supplier.MsgUpdateParam", + "authority": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", + "name": "staking_fee", + "as_coin": { + "amount": "1", + "denom": "upokt" + } + } + ] + } +} diff --git a/x/supplier/keeper/msg_server_update_param.go b/x/supplier/keeper/msg_server_update_param.go index 47e96f528..6d9a160ce 100644 --- a/x/supplier/keeper/msg_server_update_param.go +++ b/x/supplier/keeper/msg_server_update_param.go @@ -38,6 +38,9 @@ func (k msgServer) UpdateParam(ctx context.Context, msg *suppliertypes.MsgUpdate case suppliertypes.ParamMinStake: logger = logger.With("min_stake", msg.GetAsCoin()) params.MinStake = msg.GetAsCoin() + case suppliertypes.ParamStakingFee: + logger = logger.With("staking_fee", msg.GetAsCoin()) + params.StakingFee = msg.GetAsCoin() default: return nil, status.Error( codes.InvalidArgument, diff --git a/x/supplier/keeper/msg_update_params_test.go b/x/supplier/keeper/msg_update_params_test.go index 5a0019a64..5b2c45f1d 100644 --- a/x/supplier/keeper/msg_update_params_test.go +++ b/x/supplier/keeper/msg_update_params_test.go @@ -3,8 +3,10 @@ package keeper_test import ( "testing" + cosmostypes "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" + "github.com/pokt-network/poktroll/app/volatile" suppliertypes "github.com/pokt-network/poktroll/x/supplier/types" ) @@ -13,6 +15,8 @@ func TestMsgUpdateParams(t *testing.T) { params := suppliertypes.DefaultParams() require.NoError(t, k.SetParams(ctx, params)) + zerouPokt := cosmostypes.NewInt64Coin(volatile.DenomuPOKT, 0) + // default params tests := []struct { desc string @@ -42,7 +46,8 @@ func TestMsgUpdateParams(t *testing.T) { params: &suppliertypes.MsgUpdateParams{ Authority: k.GetAuthority(), Params: suppliertypes.Params{ - MinStake: &suppliertypes.DefaultMinStake, + MinStake: &suppliertypes.DefaultMinStake, + StakingFee: &zerouPokt, }, }, shouldError: false, diff --git a/x/supplier/keeper/params_test.go b/x/supplier/keeper/params_test.go index 3d74b7813..8ac48c13f 100644 --- a/x/supplier/keeper/params_test.go +++ b/x/supplier/keeper/params_test.go @@ -38,7 +38,18 @@ func TestParams_ValidateMinStake(t *testing.T) { Amount: math.NewInt(-1), }, expectedErr: suppliertypes.ErrSupplierParamInvalid.Wrapf( - "min_stake amount must be greater than 0: got -1%s", + "min_stake amount must be positive: got -1%s", + volatile.DenomuPOKT, + ), + }, + { + desc: "MinStake equal to zero", + minStake: &cosmostypes.Coin{ + Denom: volatile.DenomuPOKT, + Amount: math.NewInt(0), + }, + expectedErr: suppliertypes.ErrSupplierParamInvalid.Wrapf( + "min_stake amount must be greater than 0: got 0%s", volatile.DenomuPOKT, ), }, @@ -60,3 +71,51 @@ func TestParams_ValidateMinStake(t *testing.T) { }) } } + +func TestParams_ValidateStakingFee(t *testing.T) { + tests := []struct { + desc string + minStake any + expectedErr error + }{ + { + desc: "invalid type", + minStake: "420", + expectedErr: suppliertypes.ErrSupplierParamInvalid.Wrapf("invalid parameter type: string"), + }, + { + desc: "SupplierStakingFee less than zero", + minStake: &cosmostypes.Coin{ + Denom: volatile.DenomuPOKT, + Amount: math.NewInt(-1), + }, + expectedErr: suppliertypes.ErrSupplierParamInvalid.Wrapf( + "staking_fee amount must be positive: got -1%s", + volatile.DenomuPOKT, + ), + }, + { + desc: "zero SupplierStakingFee", + minStake: &cosmostypes.Coin{ + Denom: volatile.DenomuPOKT, + Amount: math.NewInt(0), + }, + }, + { + desc: "valid SupplierStakingFee", + minStake: &suppliertypes.DefaultStakingFee, + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + err := suppliertypes.ValidateStakingFee(test.minStake) + if test.expectedErr != nil { + require.Error(t, err) + require.Contains(t, err.Error(), test.expectedErr.Error()) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/x/supplier/types/message_update_param.go b/x/supplier/types/message_update_param.go index 0e6a1cc03..e1ce28298 100644 --- a/x/supplier/types/message_update_param.go +++ b/x/supplier/types/message_update_param.go @@ -45,23 +45,28 @@ func (msg *MsgUpdateParam) ValidateBasic() error { // Parameter name MUST be supported by this module. switch msg.Name { case ParamMinStake: - if err := msg.paramTypeIsCoin(); err != nil { + if err := genericParamTypeIs[*MsgUpdateParam_AsCoin](msg); err != nil { return err } return ValidateMinStake(msg.GetAsCoin()) + case ParamStakingFee: + if err := genericParamTypeIs[*MsgUpdateParam_AsCoin](msg); err != nil { + return err + } + return ValidateStakingFee(msg.GetAsCoin()) default: return ErrSupplierParamInvalid.Wrapf("unsupported param %q", msg.Name) } } -// paramTypeIsCoin checks if the parameter type is a Coin, returning an error if not. -func (msg *MsgUpdateParam) paramTypeIsCoin() error { - if _, ok := msg.AsType.(*MsgUpdateParam_AsCoin); !ok { +// genericParamTypeIs checks if the parameter type is T, returning an error if not. +func genericParamTypeIs[T any](msg *MsgUpdateParam) error { + if _, ok := msg.AsType.(T); !ok { return ErrSupplierParamInvalid.Wrapf( - "invalid type for param %q expected %T, got %T", - msg.Name, &MsgUpdateParam_AsCoin{}, - msg.AsType, + "invalid type for param %q; expected %T, got %T", + msg.Name, *new(T), msg.AsType, ) } + return nil } diff --git a/x/supplier/types/params.go b/x/supplier/types/params.go index 48a90f97d..7fe2e081a 100644 --- a/x/supplier/types/params.go +++ b/x/supplier/types/params.go @@ -14,6 +14,10 @@ var ( ParamMinStake = "min_stake" // TODO_MAINNET: Determine the default value. DefaultMinStake = cosmostypes.NewInt64Coin("upokt", 1000000) // 1 POKT + KeyStakingFee = []byte("StakingFee") + ParamStakingFee = "staking_fee" + // TODO_MAINNET: Determine the default value. + DefaultStakingFee = cosmostypes.NewInt64Coin("upokt", 1) // 1 uPOKT ) // ParamKeyTable the param key table for launch module @@ -22,15 +26,22 @@ func ParamKeyTable() paramtypes.KeyTable { } // NewParams creates a new Params instance -func NewParams(minStake *cosmostypes.Coin) Params { +func NewParams( + minStake *cosmostypes.Coin, + stakingFee *cosmostypes.Coin, +) Params { return Params{ - MinStake: minStake, + MinStake: minStake, + StakingFee: stakingFee, } } // DefaultParams returns a default set of parameters func DefaultParams() Params { - return NewParams(&DefaultMinStake) + return NewParams( + &DefaultMinStake, + &DefaultStakingFee, + ) } // ParamSetPairs get the params.ParamSet @@ -41,6 +52,11 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { &p.MinStake, ValidateMinStake, ), + paramtypes.NewParamSetPair( + KeyStakingFee, + &p.StakingFee, + ValidateStakingFee, + ), } } @@ -50,30 +66,58 @@ func (p Params) Validate() error { return err } + if err := ValidateStakingFee(p.StakingFee); err != nil { + return err + } + return nil } // ValidateMinStake validates the MinStake param. func ValidateMinStake(minStakeAny any) error { - minStakeCoin, ok := minStakeAny.(*cosmostypes.Coin) + minStakeCoin, err := paramAsPositiveuPOKT(minStakeAny, "min_stake") + if err != nil { + return err + } + + if minStakeCoin.IsZero() { + return ErrSupplierParamInvalid.Wrapf("min_stake amount must be greater than 0: got %s", minStakeCoin) + } + + return nil +} + +// ValidateStakingFee validates the StakingFee param. +func ValidateStakingFee(stakingFeeAny any) error { + if _, err := paramAsPositiveuPOKT(stakingFeeAny, "staking_fee"); err != nil { + return err + } + + return nil +} + +// paramAsPositiveuPOKT checks that paramAny is a *cosmostypes.Coin and that its +// amount is positive, returning an error if either is not the case. +func paramAsPositiveuPOKT(paramAny any, paramName string) (*cosmostypes.Coin, error) { + paramCoin, ok := paramAny.(*cosmostypes.Coin) if !ok { - return ErrSupplierParamInvalid.Wrapf("invalid parameter type: %T", minStakeAny) + return nil, ErrSupplierParamInvalid.Wrapf("invalid parameter type: %T", paramAny) } - if minStakeCoin == nil { - return ErrSupplierParamInvalid.Wrapf("missing min_stake") + if paramCoin == nil { + return nil, ErrSupplierParamInvalid.Wrapf("missing param") } - if minStakeCoin.Denom != volatile.DenomuPOKT { - return ErrSupplierParamInvalid.Wrapf( - "invalid min_stake denom %q; expected %q", - minStakeCoin.Denom, volatile.DenomuPOKT, + if paramCoin.Denom != volatile.DenomuPOKT { + return nil, ErrSupplierParamInvalid.Wrapf( + "invalid %s denom %q; expected %q", + paramName, paramCoin.Denom, volatile.DenomuPOKT, ) } - if minStakeCoin.IsZero() || minStakeCoin.IsNegative() { - return ErrSupplierParamInvalid.Wrapf("min_stake amount must be greater than 0: got %s", minStakeCoin) + if paramCoin.IsNegative() { + return nil, ErrSupplierParamInvalid.Wrapf("%s amount must be positive: got %s", paramName, paramCoin) } - return nil + return paramCoin, nil } diff --git a/x/supplier/types/params.pb.go b/x/supplier/types/params.pb.go index 8a79db314..06b031634 100644 --- a/x/supplier/types/params.pb.go +++ b/x/supplier/types/params.pb.go @@ -30,6 +30,8 @@ type Params struct { // min_stake is the minimum amount of uPOKT that a supplier must stake to be // included in network sessions and remain staked. MinStake *types.Coin `protobuf:"bytes,1,opt,name=min_stake,json=minStake,proto3" json:"min_stake" yaml:"min_stake"` + // staking_fee is the fee charged by the protocol for staking a supplier. + StakingFee *types.Coin `protobuf:"bytes,2,opt,name=staking_fee,json=stakingFee,proto3" json:"staking_fee" yaml:"staking_fee"` } func (m *Params) Reset() { *m = Params{} } @@ -68,6 +70,13 @@ func (m *Params) GetMinStake() *types.Coin { return nil } +func (m *Params) GetStakingFee() *types.Coin { + if m != nil { + return m.StakingFee + } + return nil +} + func init() { proto.RegisterType((*Params)(nil), "poktroll.supplier.Params") } @@ -75,25 +84,27 @@ func init() { func init() { proto.RegisterFile("poktroll/supplier/params.proto", fileDescriptor_60f7a8031a8c22d5) } var fileDescriptor_60f7a8031a8c22d5 = []byte{ - // 273 bytes of a gzipped FileDescriptorProto + // 313 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2b, 0xc8, 0xcf, 0x2e, 0x29, 0xca, 0xcf, 0xc9, 0xd1, 0x2f, 0x2e, 0x2d, 0x28, 0xc8, 0xc9, 0x4c, 0x2d, 0xd2, 0x2f, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x84, 0xc9, 0xeb, 0xc1, 0xe4, 0xa5, 0x04, 0x13, 0x73, 0x33, 0xf3, 0xf2, 0xf5, 0xc1, 0x24, 0x44, 0x95, 0x94, 0x48, 0x7a, 0x7e, 0x7a, 0x3e, 0x98, 0xa9, 0x0f, 0x62, 0x41, 0x45, 0xe5, 0x92, 0xf3, 0x8b, 0x73, 0xf3, 0x8b, 0xf5, 0x93, 0x12, 0x8b, 0x53, 0xf5, 0xcb, 0x0c, 0x93, 0x52, 0x4b, 0x12, 0x0d, 0xf5, 0x93, 0xf3, - 0x33, 0xf3, 0x20, 0xf2, 0x4a, 0x1d, 0x8c, 0x5c, 0x6c, 0x01, 0x60, 0xcb, 0x84, 0x22, 0xb9, 0x38, - 0x73, 0x33, 0xf3, 0xe2, 0x8b, 0x4b, 0x12, 0xb3, 0x53, 0x25, 0x18, 0x15, 0x18, 0x35, 0xb8, 0x8d, - 0x24, 0xf5, 0x20, 0xda, 0xf5, 0x40, 0xda, 0xf5, 0xa0, 0xda, 0xf5, 0x9c, 0xf3, 0x33, 0xf3, 0x9c, - 0x14, 0x5f, 0xdd, 0x93, 0x47, 0xa8, 0xff, 0x74, 0x4f, 0x5e, 0xa0, 0x32, 0x31, 0x37, 0xc7, 0x4a, - 0x09, 0x2e, 0xa4, 0x14, 0xc4, 0x91, 0x9b, 0x99, 0x17, 0x0c, 0x62, 0x5a, 0x29, 0xbf, 0x58, 0x20, - 0xcf, 0xd8, 0xf5, 0x7c, 0x83, 0x96, 0x14, 0xdc, 0xab, 0x15, 0x08, 0xcf, 0x42, 0xec, 0x77, 0xf2, - 0x3f, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x1b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, - 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0x0c, - 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0x41, 0x86, 0xe8, 0xe6, 0xa5, - 0x96, 0x94, 0xe7, 0x17, 0x65, 0xeb, 0x63, 0x33, 0xb1, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, - 0xec, 0x45, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc3, 0x4d, 0x0e, 0x37, 0x60, 0x01, 0x00, - 0x00, + 0x33, 0xf3, 0x20, 0xf2, 0x4a, 0xaf, 0x19, 0xb9, 0xd8, 0x02, 0xc0, 0x96, 0x09, 0x45, 0x72, 0x71, + 0xe6, 0x66, 0xe6, 0xc5, 0x17, 0x97, 0x24, 0x66, 0xa7, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x1b, + 0x49, 0xea, 0x41, 0xb4, 0xeb, 0x81, 0xb4, 0xeb, 0x41, 0xb5, 0xeb, 0x39, 0xe7, 0x67, 0xe6, 0x39, + 0x29, 0xbe, 0xba, 0x27, 0x8f, 0x50, 0xff, 0xe9, 0x9e, 0xbc, 0x40, 0x65, 0x62, 0x6e, 0x8e, 0x95, + 0x12, 0x5c, 0x48, 0x29, 0x88, 0x23, 0x37, 0x33, 0x2f, 0x18, 0xc4, 0x14, 0x4a, 0xe4, 0xe2, 0x06, + 0x89, 0x65, 0xe6, 0xa5, 0xc7, 0xa7, 0xa5, 0xa6, 0x4a, 0x30, 0x11, 0x32, 0x5c, 0xf5, 0xd5, 0x3d, + 0x79, 0x64, 0x1d, 0x9f, 0xee, 0xc9, 0x0b, 0x41, 0x8c, 0x47, 0x12, 0x54, 0x0a, 0xe2, 0x82, 0xf2, + 0xdc, 0x52, 0x53, 0xad, 0x94, 0x5f, 0x2c, 0x90, 0x67, 0xec, 0x7a, 0xbe, 0x41, 0x4b, 0x0a, 0x1e, + 0x9a, 0x15, 0x88, 0xf0, 0x84, 0x78, 0xd1, 0xc9, 0xff, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, + 0x18, 0x6f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, + 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0x32, 0x4c, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, + 0xce, 0xcf, 0xd5, 0x07, 0x19, 0xa2, 0x9b, 0x97, 0x5a, 0x52, 0x9e, 0x5f, 0x94, 0xad, 0x8f, 0xcd, + 0xc4, 0x92, 0xca, 0x82, 0xd4, 0xe2, 0x24, 0x36, 0x70, 0x28, 0x1a, 0x03, 0x02, 0x00, 0x00, 0xff, + 0xff, 0xe0, 0x47, 0xa0, 0x65, 0xc3, 0x01, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -118,6 +129,9 @@ func (this *Params) Equal(that interface{}) bool { if !this.MinStake.Equal(that1.MinStake) { return false } + if !this.StakingFee.Equal(that1.StakingFee) { + return false + } return true } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -140,6 +154,18 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.StakingFee != nil { + { + size, err := m.StakingFee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } if m.MinStake != nil { { size, err := m.MinStake.MarshalToSizedBuffer(dAtA[:i]) @@ -176,6 +202,10 @@ func (m *Params) Size() (n int) { l = m.MinStake.Size() n += 1 + l + sovParams(uint64(l)) } + if m.StakingFee != nil { + l = m.StakingFee.Size() + n += 1 + l + sovParams(uint64(l)) + } return n } @@ -250,6 +280,42 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakingFee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StakingFee == nil { + m.StakingFee = &types.Coin{} + } + if err := m.StakingFee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:])