The following document specifies the operators module.
This module allows the registration and management of metadata related to restaking operators.
Contents
Concepts
Operator
An operator is the on-chain representation of an individual or company that is responsible for running off-chain
programs for each of the services that they are partaking. Operators are responsible for the uptime and the
correct operation of the services that they are running, and can be slashed if they are found to be acting
maliciously or if they are not providing the services that they are supposed to.
When registering a new operator, it is automatically assigned a new ID, which is incremental and unique across all
operators.
// Operator defines the fields of an operator
message Operator {
// ID is the auto-generated unique identifier for the operator
uint32 id = 1 [(gogoproto.customname) = "ID"];
// Status is the status of the operator
OperatorStatus status = 2;
// Admin is the address of the user that can manage the operator
string admin = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// Moniker is the identifier of the operator
string moniker = 4;
// Website is the website of the operator
string website = 5;
// PictureURL is the URL of the picture of the operator
string picture_url = 6 [(gogoproto.customname) = "PictureURL"];
// Address is the address of the account associated to the operator.
// This will be used to store tokens that are delegated to this operator.
string address = 7 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// Tokens define the delegated tokens.
repeated cosmos.base.v1beta1.Coin tokens = 8 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.nullable) = false
];
// DelegatorShares define the total shares issued to an operator's delegators.
repeated cosmos.base.v1beta1.DecCoin delegator_shares = 9 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins",
(gogoproto.nullable) = false
];
}
An operator can have one of the following statuses:
ACTIVE: The operator is currently running the services that they are responsible for, receiving rewards for their
services and being eligible for slashing.
INACTIVATING: The operator has declared their intention of becoming inactive. In this state, an operator is no
longer eligible for rewards, but is still eligible for slashing.
INACTIVE: The operator is no longer running the services that they are responsible for, and is no longer eligible
for rewards nor slashing.
// OperatorStatus defines the possible statuses of an operator
enum OperatorStatus {
option (gogoproto.goproto_enum_prefix) = false;
// OPERATOR_STATUS_UNSPECIFIED defines an unspecified status
OPERATOR_STATUS_UNSPECIFIED = 0;
// OPERATOR_STATUS_ACTIVE identifies an active operator which is providing
// services
OPERATOR_STATUS_ACTIVE = 1;
// OPERATOR_STATUS_INACTIVATING identifies an operator that is in the process
// of becoming inactive
OPERATOR_STATUS_INACTIVATING = 2;
// OPERATOR_STATUS_INACTIVE defines an inactive operator that is not providing
// services
OPERATOR_STATUS_INACTIVE = 3;
}
Operator Params
Each operator can set a series of parameters that only apply to them. These parameters are collectively calledOperatorParams and can be edited without any previous notice from the operator's admin.
// OperatorParams represent the params that have been set for an individual
// operator.
message OperatorParams {
// CommissionRate defines the commission rate charged to delegators, as a
// fraction.
string commission_rate = 1 [
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
}
Inactivating queue
The inactivating queue is a list of operators that have declared their intention of becoming inactive. This queue is
used to keep track of the operators that are in the process of becoming inactive, and to ensure that they are not
eligible for rewards while they are in this state.
State
Params
The module params are stored using the 0x01 key:
Params: 0x01 -> ProtocolBuffer(params)
Next Operator ID
The ID that will be assigned to the next registered operator is stored using the 0xa1 key:
Next operator ID: 0xa1 -> uint32
Operators
Each operator is stored in state with the prefix of 0xa2:
The MsgRegisterOperator can be sent by anyone to register a new operator.
// MsgRegisterOperator defines the message structure for the RegisterOperator
// gRPC service method. It allows an account to register a new operator that can
// opt-in to validate various services. It requires a sender address as well as
// the details of the operator to be registered.
message MsgRegisterOperator {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/MsgRegisterOperator";
// Sender is the address of the user registering the operator
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// Moniker is the moniker of the operator
string moniker = 2 [(gogoproto.moretags) = "yaml:\"moniker\""];
// Website is the website of the operator (optional)
string website = 3 [(gogoproto.moretags) = "yaml:\"website\""];
// PictureURL is the URL of operator picture (optional)
string picture_url = 4 [
(gogoproto.moretags) = "yaml:\"picture_url\"",
(gogoproto.customname) = "PictureURL"
];
// FeeAmount represents the fees that are going to be paid to create the
// operator. These should always be greater or equals of any of the coins
// specified inside the OperatorRegistrationFee field of the modules params.
// If no fees are specified inside the module parameters, this field can be
// omitted.
repeated cosmos.base.v1beta1.Coin fee_amount = 5 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.nullable) = false
];
}
The message will fail under the following conditions:
The operator data are not valid
The user registering for the operator has not enough funds to pay for the registration fee set inside the module's
params
This message returns a MsgRegisterOperatorResponse that contains the ID of the newly registered operator.
// MsgRegisterOperatorResponse is the return value of MsgRegisterOperator.
// It returns the newly created operator ID.
message MsgRegisterOperatorResponse {
// NewOperatorID is the ID of the newly registered operator
uint32 new_operator_id = 1 [(gogoproto.customname) = "NewOperatorID"];
}
MsgUpdateOperator
The MsgUpdateOperator can be sent by the operator's admin to update the operator's data.
// MsgUpdateOperator defines the message structure for the UpdateOperator gRPC
// service method. It allows the operator owner to update the details of an
// existing operator.
message MsgUpdateOperator {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/MsgUpdateOperator";
// Sender is the address of the user updating the operator
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// OperatorID represents the ID of the operator to be updated
uint32 operator_id = 2 [(gogoproto.customname) = "OperatorID"];
// Moniker is the new moniker of the operator.
// If it shouldn't be changed, use [do-not-modify] instead.
string moniker = 3 [(gogoproto.moretags) = "yaml:\"name\""];
// Website is the new website of the operator.
// If it shouldn't be changed, use [do-not-modify] instead.
string website = 4 [(gogoproto.moretags) = "yaml:\"website\""];
// PictureURL is the new URL of the operator picture.
// If it shouldn't be changed, use [do-not-modify] instead.
string picture_url = 5 [
(gogoproto.moretags) = "yaml:\"picture_url\"",
(gogoproto.customname) = "PictureURL"
];
}
The message will fail under the following conditions:
The operator data are not valid
The user updating the operator is not the operator's admin
MsgDeactivateOperator
The MsgDeactivateOperator can be sent by the operator's admin to declare the intention of deactivating the operator,
and initiate the inactivating process.
// MsgDeactivateOperator defines the message structure for the
// DeactivateOperator gRPC service method. It allows the operator owner to
// signal that the operator will become inactive. This should be used to signal
// users that the operator is going to stop performing services and they should
// switch to another operator.
message MsgDeactivateOperator {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/MsgDeactivateOperator";
// Sender is the address of the user deactivating the operator
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// OperatorID represents the ID of the operator to be deregistered
uint32 operator_id = 2 [(gogoproto.customname) = "OperatorID"];
}
The message will fail under the following conditions:
The operator is already inactive
The user deactivating the operator is not the operator's admin
MsgReactivateOperator
The MsgReactivateOperator can be sent by the operator's admin to reactivate the operator, after it has been
deactivated.
// MsgReactivateOperator defines the message structure for the
// ReactivateOperator gRPC service method. It allows the operator owner to
// reactivate an inactive operator.
message MsgReactivateOperator {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/MsgReactivateOperator";
// Sender is the address of the user reactivating the operator
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// OperatorID represents the ID of the operator to be reactivated
uint32 operator_id = 2 [(gogoproto.customname) = "OperatorID"];
}
The message will fail under the following conditions:
The operator is not inactive
The user reactivating the operator is not the operator's admin
MsgDeleteOperator
The MsgDeleteOperator can be sent by the operator's admin to delete the operator from the state.
// MsgDeleteOperator defines the message structure for the
// DeleteOperator gRPC service method. It allows the operator owner to
// delete a deactivated operator.
message MsgDeleteOperator {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/MsgDeleteOperator";
// Sender is the address of the user deleting the operator
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// OperatorID represents the ID of the operator to be deleted
uint32 operator_id = 2 [(gogoproto.customname) = "OperatorID"];
}
The message will fail under the following conditions:
The operator is not inactive
The user deleting the operator is not the operator's admin
MsgSetOperatorParams
The MsgSetOperatorParams can be sent by the operator's admin to set the operator's params.
// MsgSetOperatorParams defines the message structure for the
// SetOperatorParams gRPC service method. It allows the operator admin to
// update the operator's parameters.
message MsgSetOperatorParams {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/MsgSetOperatorParams";
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
uint32 operator_id = 2 [(gogoproto.customname) = "OperatorID"];
OperatorParams params = 3 [(gogoproto.nullable) = false];
}
The message will fail under the following conditions:
The params are not valid
The user setting the operator's params is not the operator's admin
MsgTransferOperatorOwnership
The MsgTransferOperatorOwnership can be sent by the operator's admin to transfer the operator's ownership to another
address.
// MsgTransferOperatorOwnership defines the message structure for the
// TransferOperatorOwnership gRPC service method. It allows an operator admin to
// transfer the ownership of the operator to another account.
message MsgTransferOperatorOwnership {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/MsgTransferOperatorOwnership";
// Sender is the address of the user transferring the ownership
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// OperatorID represents the ID of the operator to transfer ownership
uint32 operator_id = 2 [(gogoproto.customname) = "OperatorID"];
// NewAdmin is the address of the new admin of the operator
string new_admin = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}
The message will fail under the following conditions:
The user transferring the operator's ownership is not the operator's admin
Events
BeginBlocker
Type
Attribute Key
Attribute Value
complete_operator_inactivation
operator_id
{operatorID}
complete_operator_inactivation
sender
{senderAddress}
Handlers
MsgRegisterOperator
Type
Attribute Key
Attribute Value
register_operator
operator_id
{operatorID}
register_operator
sender
{senderAddress}
MsgUpdateOperator
Type
Attribute Key
Attribute Value
update_operator
operator_id
{operatorID}
update_operator
sender
{senderAddress}
MsgDeactivateOperator
Type
Attribute Key
Attribute Value
start_operator_inactivation
operator_id
{operatorID}
start_operator_inactivation
sender
{senderAddress}
MsgReactivateOperator
Type
Attribute Key
Attribute Value
reactivate_operator
operator_id
{operatorID}
reactivate_operator
sender
{senderAddress}
MsgDeleteOperator
Type
Attribute Key
Attribute Value
delete_opearator
operator_id
{operatorID}
delete_opearator
sender
{senderAddress}
MsgSetOperatorParams
Type
Attribute Key
Attribute Value
set_operator_params
operator_id
{operatorID}
set_operator_params
sender
{senderAddress}
Parameters
The operators module contains the following parameters:
// Params defines the parameters for the operators module.
message Params {
// OperatorRegistrationFee represents the fee that an operator must pay in
// order to register itself with the network.
// The fee is drawn from the MsgRegisterOperator sender's account and
// transferred to the community pool.
repeated cosmos.base.v1beta1.Coin operator_registration_fee = 1 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "yaml:\"operator_creation_fee\"",
(gogoproto.nullable) = false
];
// DeactivationTime represents the amount of time that will pass between
// the time that an operator signals its willingness to deactivate and the
// time that it actually becomes inactive.
int64 deactivation_time = 2 [(gogoproto.stdduration) = true];
}