The following document specifies the services module.
This module allows the registration and management of metadata related to Actively Validated Services (AVS) within the
MilkyWay restaking protocol.
Contents
Concepts
Service
A service is the on-chain representation of an application that requires operators to run its software off-chain to
provide it with security, in exchange for rewards. Services are responsible for coding the off-chain program that need
to be run by operators, and to design their rewards distributions in order to make sure those operators are incentivized
to run their software. Also, service administrators are responsible for monitoring the off-chain execution of their
software, and to slash any operator that misbehaves.
When registering a new service, it is automatically assigned a new ID, which is incremental and unique across all
services.
// Service defines the fields of a service
message Service {
// ID is the unique identifier of the service
uint32 id = 1 [(gogoproto.customname) = "ID"];
// Status is the status of the service
ServiceStatus status = 2;
// Admin is the address of the user that has administrative power over the
// service
string admin = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// Name is the name of the service
string name = 4;
// Description is the description of the service
string description = 5;
// Website is the website of the service
string website = 6;
// PictureURL is the URL of the picture of the service
string picture_url = 7 [(gogoproto.customname) = "PictureURL"];
// Address is the address of the account associated with the service.
// This will be used in order to store all the tokens that are delegated to
// this service by various users.
string address = 8 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// Tokens define the delegated tokens.
repeated cosmos.base.v1beta1.Coin tokens = 9 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.nullable) = false
];
// DelegatorShares define the total shares issued to a service's delegators.
repeated cosmos.base.v1beta1.DecCoin delegator_shares = 10 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins",
(gogoproto.nullable) = false
];
// Accredited defines if the service is accredited.
// Note: We use this term instead of "trusted" of "verified" in order to
// represent something more generic.
// Initially, services will be accredited by the on-chain governance process.
// In the future, we may add more ways to accredit services (e.g. automatic
// ones based on the operators that decide to run the service, or the amount
// of cryptoeconomic security that the service was able to capture).
bool accredited = 11;
}
A service can have one of the following statuses:
CREATED: the service has been created but is not yet active.
ACTIVE: the service is currently running and accepting for operators to validate it. This means that it's
distributing rewards to operators and is monitoring their behavior.
INACTIVE: the service is not currently running and is not accepting for operators to validate it. this means that
it's not distributing rewards to operators and is not monitoring their behavior.
// ServiceStatus defines the status of a service
enum ServiceStatus {
option (gogoproto.goproto_enum_prefix) = false;
// SERVICE_STATUS_UNSPECIFIED defines an unspecified status
SERVICE_STATUS_UNSPECIFIED = 0;
// SERVICE_STATUS_CREATED identifies a recently created service that is not
// yet active
SERVICE_STATUS_CREATED = 1;
// SERVICE_STATUS_ACTIVE identifies an active service
SERVICE_STATUS_ACTIVE = 2;
// SERVICE_STATUS_INACTIVE identifies an inactive service
SERVICE_STATUS_INACTIVE = 3;
}
Service params
Each service can set a series of parameters that only apply to them. These are collectively known as the service params
and can be edited without any notice from the service admin.
// ServiceParams defines the parameters of a service
message ServiceParams {
// AllowedDenoms defines the list of denoms that can be restaked toward
// the service. If the list is empty, any denom can be used.
repeated string allowed_denoms = 1;
}
State
Params
The module params are stored using the 0x01 key:
Params: 0x01 -> ProtocolBuffer(params)
Next Service ID
The ID that will be assigned to the next registered service is stored using the 0xa1 key:
Next service ID: 0xa1 -> uint32
Services
Each service is stored in state with the prefix of 0xa2:
In order to know more easily and faster if a particular address represents a service, we store the set of service
addresses using the 0xa3 prefix:
Service address: 0xa3 | ServiceAddress -> []byte{}
Service params
Each service's params are stored using the 0xa4 prefix:
Service params: 0xa4 | ServiceID -> ProtocolBuffer(ServiceParams)
Messages
MsgCreteService
The MsgCreateService can be sent by anyone to create a new service.
// MsgCreateServiceResponse defines the message structure for the
// CreateService gRPC service method. It allows an account to register a new
// service that can be validated by operators. It requires a sender address
// as well as the details of the service to be registered.
message MsgCreateService {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/services/MsgCreateService";
// Sender is the address of the user registering the service
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// Name is the name of the service
string name = 2 [(gogoproto.moretags) = "yaml:\"name\""];
// Description is the description of the service
string description = 3 [(gogoproto.moretags) = "yaml:\"description\""];
// Website is the website of the service
string website = 4 [(gogoproto.moretags) = "yaml:\"website\""];
// PictureURL is the URL of the service picture
string picture_url = 5 [
(gogoproto.moretags) = "yaml:\"picture_url\"",
(gogoproto.customname) = "PictureURL"
];
// FeeAmount represents the fees that are going to be paid to create the
// service. These should always be greater or equals of any of the coins
// specified inside the ServiceRegistrationFee 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 = 6 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.nullable) = false
];
}
The message will fail under the following conditions:
The service data are not valid
The user creating the service has not enough funds to pay for the creation fee set inside the module's params
This message returns a MsgCreateServiceResponse that contains the ID of the newly created service.
// MsgCreateServiceResponse is the return value of MsgCreateService.
// It returns the newly created service ID.
message MsgCreateServiceResponse {
// NewServiceID is the ID of the newly registered service
uint32 new_service_id = 1 [(gogoproto.customname) = "NewServiceID"];
}
MsgUpdateService
The MsgUpdateService can be sent by the service admin to update the service's data.
// MsgUpdateService defines the message structure for the UpdateService gRPC
// service method. It allows the service admin to update the details of
// an existing service.
message MsgUpdateService {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/services/MsgUpdateService";
// Sender is the address of the user updating the service
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// ID represents the ID of the service to be updated
uint32 service_id = 2 [(gogoproto.customname) = "ServiceID"];
// Name is the new name of the service.
// If it shouldn't be changed, use [do-not-modify] instead.
string name = 3 [(gogoproto.moretags) = "yaml:\"name\""];
// Description is the new description of the service.
// If it shouldn't be changed, use [do-not-modify] instead.
string description = 4 [(gogoproto.moretags) = "yaml:\"description\""];
// Website is the new website of the service.
// If it shouldn't be changed, use [do-not-modify] instead.
string website = 5 [(gogoproto.moretags) = "yaml:\"website\""];
// PictureURL is the new URL of the service picture.
// If it shouldn't be changed, use [do-not-modify] instead.
string picture_url = 6 [
(gogoproto.moretags) = "yaml:\"picture_url\"",
(gogoproto.customname) = "PictureURL"
];
}
The message will fail under the following conditions:
The service data are not valid
The user updating the service is not the service admin
MsgActivateService
The MsgActivateService can be sent by the service admin to activate the service.
// MsgActivateService defines the message structure for the ActivateService gRPC
message MsgActivateService {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/MsgActivateService";
// Sender is the address of the user that wants to activate the service
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// ServiceID represents the ID of the service to be activated
uint32 service_id = 2 [(gogoproto.customname) = "ServiceID"];
}
The message will fail under the following conditions:
The service is already active
The user activating the service is not the service admin
MsgDeactivateService
The MsgDeactivateService can be sent by the service admin to deactivate the service.
// MsgDeactivateService defines the message structure for the DeactivateService
// gRPC service method. It allows the service admin to deactivate an existing
// service.
message MsgDeactivateService {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/MsgDeactivateService";
// Sender is the address of the user that wants to deactivate the service
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// ServiceID represents the ID of the service to be deactivated
uint32 service_id = 2 [(gogoproto.customname) = "ServiceID"];
}
The message will fail under the following conditions:
The service is already inactive
The user deactivating the service is not the service admin
MsgDeleteService
The MsgDeleteService can be sent by the service admin to delete the service.
// MsgDeleteService defines the message structure for the DeleteService
// gRPC service method. It allows the service admin to delete a previously
// deactivated service
message MsgDeleteService {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/MsgDeleteService";
// Sender is the address of the user that wants to delete the service
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// ServiceID represents the ID of the service to be deleted
uint32 service_id = 2 [(gogoproto.customname) = "ServiceID"];
}
The message will fail under the following conditions:
The user deleting the service is not the service admin
MsgTransferServiceOwnership
The MsgTransferServiceOwnership can be sent by the service admin to transfer the ownership of the service to another
address.
// MsgTransferServiceOwnership defines the message structure for the
// TransferServiceOwnership gRPC service method. It allows a service admin to
// transfer the ownership of the service to another account.
message MsgTransferServiceOwnership {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/MsgTransferServiceOwnership";
// Sender is the address of the user transferring the ownership
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// ServiceID represents the ID of the service to transfer ownership
uint32 service_id = 2 [(gogoproto.customname) = "ServiceID"];
// NewAdmin is the address of the new admin of the service
string new_admin = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}
The message will fail under the following conditions:
The user transferring the service's ownership is not the service admin
MsgSetServiceParams
The MsgSetServiceParams can be sent by the service admin to set the service's params.
// MsgSetServiceParams defines the message structure for the
// SetServiceParams gRPC service method. It allows a service admin to
// update the parameters of a service.
message MsgSetServiceParams {
option (cosmos.msg.v1.signer) = "sender";
option (amino.name) = "milkyway/MsgSetServiceParams";
// Sender is the address of the user setting the parameters
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// ServiceID is the ID of the service whose parameters are being set
uint32 service_id = 2 [(gogoproto.customname) = "ServiceID"];
// ServiceParams defines the new parameters of the service
ServiceParams service_params = 3 [(gogoproto.nullable) = false];
}
The message will fail under the following conditions:
The params are not valid
The user setting the service's params is not the service admin
MsgAccreditService
The MsgAccreditService can be sent by the gov module to recognize a service as "accredited".
// MsgAccreditService defines the message structure for the AccreditService gRPC
// service method. It allows the authority to accredit a service.
message MsgAccreditService {
option (cosmos.msg.v1.signer) = "authority";
option (amino.name) = "milkyway/MsgAccreditService";
// Authority is the address that controls the module (defaults to x/gov unless
// overwritten).
string authority = 1 [
(gogoproto.moretags) = "yaml:\"authority\"",
(cosmos_proto.scalar) = "cosmos.AddressString"
];
// ServiceID represents the ID of the service to be accredited
uint32 service_id = 2 [(gogoproto.customname) = "ServiceID"];
}
The message will fail under the following conditions:
The sender is not the god module account
MsgRevokeServiceAccreditation
The MsgRevokeServiceAccreditation can be sent by the gov module to revoke the accreditation of a service.
// MsgRevokeServiceAccreditation defines the message structure for the
// RevokeServiceAccreditation gRPC service method. It allows the authority to
// revoke a service's accreditation.
message MsgRevokeServiceAccreditation {
option (cosmos.msg.v1.signer) = "authority";
option (amino.name) = "milkyway/MsgRevokeServiceAccreditation";
// Authority is the address that controls the module (defaults to x/gov unless
// overwritten).
string authority = 1 [
(gogoproto.moretags) = "yaml:\"authority\"",
(cosmos_proto.scalar) = "cosmos.AddressString"
];
// ServiceID represents the ID of the service to have its accreditation
// revoked
uint32 service_id = 2 [(gogoproto.customname) = "ServiceID"];
}
The message will fail under the following conditions:
The sender is not the god module account
Events
Handlers
MsgCreateService
Type
Attribute Key
Attribute Value
create_service
service_id
{serviceID}
create_service
sender
{senderAddress}
MsgUpdateService
Type
Attribute Key
Attribute Value
update_service
service_id
{serviceID}
update_service
sender
{senderAddress}
MsgActivateService
Type
Attribute Key
Attribute Value
activate_service
service_id
{serviceID}
activate_service
sender
{senderAddress}
MsgDeactivateService
Type
Attribute Key
Attribute Value
deactivate_service
service_id
{serviceID}
deactivate_service
sender
{senderAddress}
MsgDeleteService
Type
Attribute Key
Attribute Value
delete_service
service_id
{serviceID}
delete_service
sender
{senderAddress}
MsgTransferServiceOwnership
Type
Attribute Key
Attribute Value
transfer_service_ownership
service_id
{serviceID}
transfer_service_ownership
new_admin
{newAdminAddress}
transfer_service_ownership
sender
{senderAddress}
MsgSetServiceParams
Type
Attribute Key
Attribute Value
set_service_params
service_id
{serviceID}
set_service_params
sender
{senderAddress}
MsgAccreditService
Type
Attribute Key
Attribute Value
accredit_service
service_id
{serviceID}
MsgRevokeServiceAccreditation
Type
Attribute Key
Attribute Value
revoke_service_accreditation
service_id
{serviceID}
Params
The services module contains the following parameters:
// Params defines the parameters for the module.
message Params {
// ServiceRegistrationFee defines the fee to register a new service.
// The fee is drawn from the MsgRegisterService sender's account,
// and transferred to the community pool.
repeated cosmos.base.v1beta1.Coin service_registration_fee = 1 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "yaml:\"service_registration_fee\"",
(gogoproto.nullable) = false
];
}