mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 09:21:39 +00:00
560 lines
21 KiB
Go
560 lines
21 KiB
Go
// Package svc provides a client interface for interacting with the Sonr SVC (Service) module.
|
|
package svc
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
"github.com/cosmos/cosmos-sdk/types/tx"
|
|
|
|
"github.com/sonr-io/sonr/client/config"
|
|
"github.com/sonr-io/sonr/client/errors"
|
|
svctypes "github.com/sonr-io/sonr/x/svc/types"
|
|
)
|
|
|
|
// Client provides an interface for interacting with the SVC module.
|
|
type Client interface {
|
|
// Service Operations
|
|
RegisterService(ctx context.Context, opts *RegisterServiceOptions) (*Service, error)
|
|
UpdateService(ctx context.Context, serviceID string, opts *UpdateServiceOptions) (*Service, error)
|
|
DeregisterService(ctx context.Context, serviceID string) error
|
|
GetService(ctx context.Context, serviceID string) (*Service, error)
|
|
|
|
// Service Discovery
|
|
DiscoverServices(ctx context.Context, query *ServiceQuery) (*ServiceDiscoveryResponse, error)
|
|
ListServices(ctx context.Context, opts *ListServicesOptions) (*ServiceListResponse, error)
|
|
SearchServices(ctx context.Context, searchTerm string) (*ServiceSearchResponse, error)
|
|
|
|
// Domain Operations
|
|
RegisterDomain(ctx context.Context, opts *RegisterDomainOptions) (*Domain, error)
|
|
VerifyDomain(ctx context.Context, domain string) (*DomainVerification, error)
|
|
GetDomain(ctx context.Context, domain string) (*Domain, error)
|
|
ListDomains(ctx context.Context, opts *ListDomainsOptions) (*DomainListResponse, error)
|
|
|
|
// Service Capabilities
|
|
AddCapability(ctx context.Context, serviceID string, capability *Capability) error
|
|
RemoveCapability(ctx context.Context, serviceID string, capabilityID string) error
|
|
ListCapabilities(ctx context.Context, serviceID string) ([]*Capability, error)
|
|
|
|
// Service Endpoints
|
|
AddEndpoint(ctx context.Context, serviceID string, endpoint *Endpoint) error
|
|
UpdateEndpoint(ctx context.Context, serviceID string, endpointID string, opts *UpdateEndpointOptions) error
|
|
RemoveEndpoint(ctx context.Context, serviceID string, endpointID string) error
|
|
|
|
// Service Health
|
|
CheckServiceHealth(ctx context.Context, serviceID string) (*HealthStatus, error)
|
|
UpdateServiceHealth(ctx context.Context, serviceID string, status *HealthStatus) error
|
|
}
|
|
|
|
// Service represents a registered service.
|
|
type Service struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description,omitempty"`
|
|
Owner string `json:"owner"`
|
|
Domain string `json:"domain,omitempty"`
|
|
Version string `json:"version"`
|
|
Type string `json:"type"`
|
|
Endpoints []*Endpoint `json:"endpoints"`
|
|
Capabilities []*Capability `json:"capabilities"`
|
|
Metadata map[string]any `json:"metadata,omitempty"`
|
|
HealthStatus *HealthStatus `json:"health_status,omitempty"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at,omitempty"`
|
|
Tags []string `json:"tags,omitempty"`
|
|
}
|
|
|
|
// RegisterServiceOptions configures service registration.
|
|
type RegisterServiceOptions struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description,omitempty"`
|
|
Domain string `json:"domain,omitempty"`
|
|
Version string `json:"version"`
|
|
Type string `json:"type"`
|
|
Endpoints []*Endpoint `json:"endpoints"`
|
|
Capabilities []*Capability `json:"capabilities,omitempty"`
|
|
Metadata map[string]any `json:"metadata,omitempty"`
|
|
Tags []string `json:"tags,omitempty"`
|
|
}
|
|
|
|
// UpdateServiceOptions configures service updates.
|
|
type UpdateServiceOptions struct {
|
|
Description string `json:"description,omitempty"`
|
|
Version string `json:"version,omitempty"`
|
|
Metadata map[string]any `json:"metadata,omitempty"`
|
|
Tags []string `json:"tags,omitempty"`
|
|
}
|
|
|
|
// Endpoint represents a service endpoint.
|
|
type Endpoint struct {
|
|
ID string `json:"id"`
|
|
URL string `json:"url"`
|
|
Type string `json:"type"` // REST, GraphQL, gRPC, WebSocket, etc.
|
|
Method string `json:"method,omitempty"`
|
|
Headers map[string]string `json:"headers,omitempty"`
|
|
Metadata map[string]any `json:"metadata,omitempty"`
|
|
Enabled bool `json:"enabled"`
|
|
}
|
|
|
|
// UpdateEndpointOptions configures endpoint updates.
|
|
type UpdateEndpointOptions struct {
|
|
URL string `json:"url,omitempty"`
|
|
Headers map[string]string `json:"headers,omitempty"`
|
|
Metadata map[string]any `json:"metadata,omitempty"`
|
|
Enabled *bool `json:"enabled,omitempty"`
|
|
}
|
|
|
|
// Capability represents a service capability.
|
|
type Capability struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description,omitempty"`
|
|
Type string `json:"type"`
|
|
Schema map[string]any `json:"schema,omitempty"`
|
|
Metadata map[string]any `json:"metadata,omitempty"`
|
|
Enabled bool `json:"enabled"`
|
|
}
|
|
|
|
// ServiceQuery defines query parameters for service discovery.
|
|
type ServiceQuery struct {
|
|
Type string `json:"type,omitempty"`
|
|
Domain string `json:"domain,omitempty"`
|
|
Tags []string `json:"tags,omitempty"`
|
|
Capabilities []string `json:"capabilities,omitempty"`
|
|
Metadata map[string]string `json:"metadata,omitempty"`
|
|
HealthStatus string `json:"health_status,omitempty"`
|
|
}
|
|
|
|
// ServiceDiscoveryResponse contains service discovery results.
|
|
type ServiceDiscoveryResponse struct {
|
|
Services []*Service `json:"services"`
|
|
TotalCount uint64 `json:"total_count"`
|
|
Query *ServiceQuery `json:"query"`
|
|
}
|
|
|
|
// ListServicesOptions configures service listing.
|
|
type ListServicesOptions struct {
|
|
Owner string `json:"owner,omitempty"`
|
|
Type string `json:"type,omitempty"`
|
|
Limit uint64 `json:"limit,omitempty"`
|
|
Offset uint64 `json:"offset,omitempty"`
|
|
}
|
|
|
|
// ServiceListResponse contains a list of services.
|
|
type ServiceListResponse struct {
|
|
Services []*Service `json:"services"`
|
|
TotalCount uint64 `json:"total_count"`
|
|
Limit uint64 `json:"limit"`
|
|
Offset uint64 `json:"offset"`
|
|
}
|
|
|
|
// ServiceSearchResponse contains service search results.
|
|
type ServiceSearchResponse struct {
|
|
Services []*Service `json:"services"`
|
|
TotalCount uint64 `json:"total_count"`
|
|
SearchTerm string `json:"search_term"`
|
|
}
|
|
|
|
// Domain represents a registered domain.
|
|
type Domain struct {
|
|
Name string `json:"name"`
|
|
Owner string `json:"owner"`
|
|
Verified bool `json:"verified"`
|
|
Verification *DomainVerification `json:"verification,omitempty"`
|
|
Metadata map[string]any `json:"metadata,omitempty"`
|
|
RegisteredAt string `json:"registered_at"`
|
|
ExpiresAt string `json:"expires_at,omitempty"`
|
|
}
|
|
|
|
// RegisterDomainOptions configures domain registration.
|
|
type RegisterDomainOptions struct {
|
|
Name string `json:"name"`
|
|
Metadata map[string]any `json:"metadata,omitempty"`
|
|
ExpiresAt string `json:"expires_at,omitempty"`
|
|
}
|
|
|
|
// DomainVerification contains domain verification information.
|
|
type DomainVerification struct {
|
|
Method string `json:"method"` // DNS, HTTP, File
|
|
Token string `json:"token"` // Verification token
|
|
Challenge string `json:"challenge"` // Challenge string
|
|
Verified bool `json:"verified"`
|
|
VerifiedAt string `json:"verified_at,omitempty"`
|
|
ExpiresAt string `json:"expires_at,omitempty"`
|
|
}
|
|
|
|
// ListDomainsOptions configures domain listing.
|
|
type ListDomainsOptions struct {
|
|
Owner string `json:"owner,omitempty"`
|
|
Verified *bool `json:"verified,omitempty"`
|
|
Limit uint64 `json:"limit,omitempty"`
|
|
Offset uint64 `json:"offset,omitempty"`
|
|
}
|
|
|
|
// DomainListResponse contains a list of domains.
|
|
type DomainListResponse struct {
|
|
Domains []*Domain `json:"domains"`
|
|
TotalCount uint64 `json:"total_count"`
|
|
Limit uint64 `json:"limit"`
|
|
Offset uint64 `json:"offset"`
|
|
}
|
|
|
|
// HealthStatus represents service health status.
|
|
type HealthStatus struct {
|
|
Status string `json:"status"` // healthy, unhealthy, degraded, unknown
|
|
LastChecked string `json:"last_checked"`
|
|
Message string `json:"message,omitempty"`
|
|
Metrics map[string]any `json:"metrics,omitempty"`
|
|
Uptime string `json:"uptime,omitempty"`
|
|
}
|
|
|
|
// client implements the SVC Client interface.
|
|
type client struct {
|
|
grpcConn *grpc.ClientConn
|
|
config *config.NetworkConfig
|
|
|
|
// Service clients for SVC module
|
|
queryClient svctypes.QueryClient
|
|
msgClient svctypes.MsgClient
|
|
txClient tx.ServiceClient
|
|
}
|
|
|
|
// NewClient creates a new SVC module client.
|
|
func NewClient(grpcConn *grpc.ClientConn, cfg *config.NetworkConfig) Client {
|
|
return &client{
|
|
grpcConn: grpcConn,
|
|
config: cfg,
|
|
queryClient: svctypes.NewQueryClient(grpcConn),
|
|
msgClient: svctypes.NewMsgClient(grpcConn),
|
|
txClient: tx.NewServiceClient(grpcConn),
|
|
}
|
|
}
|
|
|
|
// RegisterService registers a new service.
|
|
func (c *client) RegisterService(ctx context.Context, opts *RegisterServiceOptions) (*Service, error) {
|
|
// TODO: Implement service registration using SVC module
|
|
// Should build MsgRegisterService with proper validation
|
|
// Submit transaction to chain and wait for confirmation
|
|
// Handle domain verification if domain is provided
|
|
// Return complete service record with generated ID
|
|
|
|
return nil, errors.NewModuleError("svc", "RegisterService",
|
|
fmt.Errorf("service registration not yet implemented"))
|
|
}
|
|
|
|
// UpdateService updates an existing service.
|
|
func (c *client) UpdateService(ctx context.Context, serviceID string, opts *UpdateServiceOptions) (*Service, error) {
|
|
// TODO: Implement service updates using SVC module
|
|
// Should validate service ownership and permissions
|
|
// Build MsgUpdateService with selective field updates
|
|
// Preserve existing endpoints and capabilities unless modified
|
|
// Return updated service record
|
|
|
|
return nil, errors.NewModuleError("svc", "UpdateService",
|
|
fmt.Errorf("service updates not yet implemented"))
|
|
}
|
|
|
|
// DeregisterService deregisters a service.
|
|
func (c *client) DeregisterService(ctx context.Context, serviceID string) error {
|
|
// TODO: Implement service deregistration using SVC module
|
|
// Should validate service ownership before deregistration
|
|
// Build MsgDeregisterService and submit to chain
|
|
// Clean up associated domain registrations and capabilities
|
|
// Handle graceful shutdown of service endpoints
|
|
|
|
return errors.NewModuleError("svc", "DeregisterService",
|
|
fmt.Errorf("service deregistration not yet implemented"))
|
|
}
|
|
|
|
// GetService retrieves a service by ID.
|
|
func (c *client) GetService(ctx context.Context, serviceID string) (*Service, error) {
|
|
// TODO: Implement service retrieval using SVC query client
|
|
// Should query chain state for service record
|
|
// Convert protobuf service to client Service type
|
|
// Include current health status and endpoint information
|
|
// Handle service not found errors gracefully
|
|
|
|
return nil, errors.NewModuleError("svc", "GetService",
|
|
fmt.Errorf("service retrieval not yet implemented"))
|
|
}
|
|
|
|
// DiscoverServices discovers services based on query criteria.
|
|
func (c *client) DiscoverServices(ctx context.Context, query *ServiceQuery) (*ServiceDiscoveryResponse, error) {
|
|
// TODO: Implement service discovery using SVC module
|
|
// Should support filtering by type, domain, tags, capabilities
|
|
// Query chain state with proper pagination
|
|
// Filter results by health status if specified
|
|
// Return ranked results based on relevance
|
|
|
|
return nil, errors.NewModuleError("svc", "DiscoverServices",
|
|
fmt.Errorf("service discovery not yet implemented"))
|
|
}
|
|
|
|
// ListServices lists services with pagination.
|
|
func (c *client) ListServices(ctx context.Context, opts *ListServicesOptions) (*ServiceListResponse, error) {
|
|
// TODO: Implement service listing using SVC module
|
|
// Should support pagination with limit/offset
|
|
// Filter by owner and service type if specified
|
|
// Return services with basic metadata and status
|
|
// Handle empty result sets gracefully
|
|
|
|
return nil, errors.NewModuleError("svc", "ListServices",
|
|
fmt.Errorf("service listing not yet implemented"))
|
|
}
|
|
|
|
// SearchServices searches for services by term.
|
|
func (c *client) SearchServices(ctx context.Context, searchTerm string) (*ServiceSearchResponse, error) {
|
|
// TODO: Implement service search using SVC module
|
|
// Should search service names, descriptions, and tags
|
|
// Support fuzzy matching and relevance scoring
|
|
// Query multiple fields with OR logic
|
|
// Return results ranked by relevance
|
|
|
|
return nil, errors.NewModuleError("svc", "SearchServices",
|
|
fmt.Errorf("service search not yet implemented"))
|
|
}
|
|
|
|
// RegisterDomain registers a new domain.
|
|
func (c *client) RegisterDomain(ctx context.Context, opts *RegisterDomainOptions) (*Domain, error) {
|
|
// TODO: Implement domain registration using SVC module
|
|
// Should validate domain name format and availability
|
|
// Build MsgInitiateDomainVerification and submit to chain
|
|
// Generate verification challenge tokens
|
|
// Return domain record with verification instructions
|
|
|
|
return nil, errors.NewModuleError("svc", "RegisterDomain",
|
|
fmt.Errorf("domain registration not yet implemented"))
|
|
}
|
|
|
|
// VerifyDomain verifies domain ownership.
|
|
func (c *client) VerifyDomain(ctx context.Context, domain string) (*DomainVerification, error) {
|
|
// TODO: Implement domain verification using SVC module
|
|
// Should check DNS records, HTTP endpoints, or file verification
|
|
// Build MsgVerifyDomain and submit proof to chain
|
|
// Update domain status to verified upon success
|
|
// Handle verification failures with clear error messages
|
|
|
|
return nil, errors.NewModuleError("svc", "VerifyDomain",
|
|
fmt.Errorf("domain verification not yet implemented"))
|
|
}
|
|
|
|
// GetDomain retrieves domain information.
|
|
func (c *client) GetDomain(ctx context.Context, domain string) (*Domain, error) {
|
|
// TODO: Implement domain retrieval using SVC query client
|
|
// Should query chain state for domain registration
|
|
// Include verification status and expiration information
|
|
// Convert protobuf domain to client Domain type
|
|
// Handle domain not found cases
|
|
|
|
return nil, errors.NewModuleError("svc", "GetDomain",
|
|
fmt.Errorf("domain retrieval not yet implemented"))
|
|
}
|
|
|
|
// ListDomains lists domains with pagination.
|
|
func (c *client) ListDomains(ctx context.Context, opts *ListDomainsOptions) (*DomainListResponse, error) {
|
|
// TODO: Implement domain listing using SVC module
|
|
// Should support pagination and filtering by owner
|
|
// Filter by verification status if specified
|
|
// Return domains with metadata and expiration info
|
|
// Handle empty result sets
|
|
|
|
return nil, errors.NewModuleError("svc", "ListDomains",
|
|
fmt.Errorf("domain listing not yet implemented"))
|
|
}
|
|
|
|
// AddCapability adds a capability to a service.
|
|
func (c *client) AddCapability(ctx context.Context, serviceID string, capability *Capability) error {
|
|
// TODO: Implement capability addition using SVC module
|
|
// Should validate service ownership and capability schema
|
|
// Build MsgAddCapability and submit to chain
|
|
// Update service record with new capability
|
|
// Validate capability name uniqueness within service
|
|
|
|
return errors.NewModuleError("svc", "AddCapability",
|
|
fmt.Errorf("capability addition not yet implemented"))
|
|
}
|
|
|
|
// RemoveCapability removes a capability from a service.
|
|
func (c *client) RemoveCapability(ctx context.Context, serviceID string, capabilityID string) error {
|
|
// TODO: Implement capability removal using SVC module
|
|
// Should validate service ownership and capability existence
|
|
// Build MsgRemoveCapability and submit to chain
|
|
// Check for dependent services using this capability
|
|
// Handle cascading capability removal safely
|
|
|
|
return errors.NewModuleError("svc", "RemoveCapability",
|
|
fmt.Errorf("capability removal not yet implemented"))
|
|
}
|
|
|
|
// ListCapabilities lists service capabilities.
|
|
func (c *client) ListCapabilities(ctx context.Context, serviceID string) ([]*Capability, error) {
|
|
// TODO: Implement capability listing using SVC module
|
|
// Should query service record for capabilities
|
|
// Return capabilities with schemas and metadata
|
|
// Include capability status (enabled/disabled)
|
|
// Handle service not found errors
|
|
|
|
return nil, errors.NewModuleError("svc", "ListCapabilities",
|
|
fmt.Errorf("capability listing not yet implemented"))
|
|
}
|
|
|
|
// AddEndpoint adds an endpoint to a service.
|
|
func (c *client) AddEndpoint(ctx context.Context, serviceID string, endpoint *Endpoint) error {
|
|
// TODO: Implement endpoint addition using SVC module
|
|
// Should validate service ownership and endpoint URL format
|
|
// Build MsgAddEndpoint and submit to chain
|
|
// Validate endpoint accessibility if enabled
|
|
// Update service record with new endpoint
|
|
|
|
return errors.NewModuleError("svc", "AddEndpoint",
|
|
fmt.Errorf("endpoint addition not yet implemented"))
|
|
}
|
|
|
|
// UpdateEndpoint updates a service endpoint.
|
|
func (c *client) UpdateEndpoint(ctx context.Context, serviceID string, endpointID string, opts *UpdateEndpointOptions) error {
|
|
// TODO: Implement endpoint updates using SVC module
|
|
// Should validate service ownership and endpoint existence
|
|
// Build MsgUpdateEndpoint with selective field updates
|
|
// Validate new URL format and accessibility
|
|
// Preserve existing headers and metadata unless modified
|
|
|
|
return errors.NewModuleError("svc", "UpdateEndpoint",
|
|
fmt.Errorf("endpoint updates not yet implemented"))
|
|
}
|
|
|
|
// RemoveEndpoint removes an endpoint from a service.
|
|
func (c *client) RemoveEndpoint(ctx context.Context, serviceID string, endpointID string) error {
|
|
// TODO: Implement endpoint removal using SVC module
|
|
// Should validate service ownership and endpoint existence
|
|
// Build MsgRemoveEndpoint and submit to chain
|
|
// Check if endpoint is primary before removal
|
|
// Handle graceful endpoint shutdown
|
|
|
|
return errors.NewModuleError("svc", "RemoveEndpoint",
|
|
fmt.Errorf("endpoint removal not yet implemented"))
|
|
}
|
|
|
|
// CheckServiceHealth checks the health status of a service.
|
|
func (c *client) CheckServiceHealth(ctx context.Context, serviceID string) (*HealthStatus, error) {
|
|
// TODO: Implement health checking using SVC module
|
|
// Should query service endpoints for health status
|
|
// Aggregate health across multiple endpoints
|
|
// Check endpoint response times and error rates
|
|
// Return comprehensive health report with metrics
|
|
|
|
return nil, errors.NewModuleError("svc", "CheckServiceHealth",
|
|
fmt.Errorf("health checking not yet implemented"))
|
|
}
|
|
|
|
// UpdateServiceHealth updates the health status of a service.
|
|
func (c *client) UpdateServiceHealth(ctx context.Context, serviceID string, status *HealthStatus) error {
|
|
// TODO: Implement health status updates using SVC module
|
|
// Should validate service ownership and status format
|
|
// Build MsgUpdateServiceHealth and submit to chain
|
|
// Update service discovery with new health status
|
|
// Store health metrics and historical data
|
|
|
|
return errors.NewModuleError("svc", "UpdateServiceHealth",
|
|
fmt.Errorf("health status updates not yet implemented"))
|
|
}
|
|
|
|
// Utility functions
|
|
|
|
// GenerateServiceID generates a unique service ID.
|
|
func GenerateServiceID(name string) string {
|
|
// TODO: Implement proper service ID generation
|
|
return fmt.Sprintf("svc_%s_%d", name, time.Now().UnixNano())
|
|
}
|
|
|
|
// ValidateServiceName validates a service name.
|
|
func ValidateServiceName(name string) error {
|
|
if len(name) == 0 {
|
|
return fmt.Errorf("service name cannot be empty")
|
|
}
|
|
|
|
if len(name) > 100 {
|
|
return fmt.Errorf("service name too long")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// CreateDefaultEndpoint creates a default HTTP endpoint.
|
|
func CreateDefaultEndpoint(url string) *Endpoint {
|
|
return &Endpoint{
|
|
ID: fmt.Sprintf("endpoint_%d", time.Now().UnixNano()),
|
|
URL: url,
|
|
Type: "REST",
|
|
Method: "GET",
|
|
Enabled: true,
|
|
}
|
|
}
|
|
|
|
// CreateHealthyStatus creates a healthy status.
|
|
func CreateHealthyStatus() *HealthStatus {
|
|
return &HealthStatus{
|
|
Status: "healthy",
|
|
LastChecked: time.Now().UTC().Format(time.RFC3339),
|
|
Message: "Service is operating normally",
|
|
}
|
|
}
|
|
|
|
// Message Builders - These create the actual transaction messages
|
|
|
|
// BuildMsgRegisterService builds a MsgRegisterService message.
|
|
func BuildMsgRegisterService(creator string, opts *RegisterServiceOptions) (*svctypes.MsgRegisterService, error) {
|
|
if opts == nil {
|
|
return nil, fmt.Errorf("options cannot be nil")
|
|
}
|
|
|
|
if err := ValidateServiceName(opts.Name); err != nil {
|
|
return nil, fmt.Errorf("invalid service name: %w", err)
|
|
}
|
|
|
|
// Generate service ID if not provided
|
|
serviceID := GenerateServiceID(opts.Name)
|
|
|
|
// Extract requested permissions from capabilities
|
|
var requestedPermissions []string
|
|
for _, cap := range opts.Capabilities {
|
|
if cap != nil {
|
|
requestedPermissions = append(requestedPermissions, cap.Name)
|
|
}
|
|
}
|
|
|
|
return &svctypes.MsgRegisterService{
|
|
Creator: creator,
|
|
ServiceId: serviceID,
|
|
Domain: opts.Domain,
|
|
RequestedPermissions: requestedPermissions,
|
|
UcanDelegationChain: "", // Will be set if UCAN is used
|
|
}, nil
|
|
}
|
|
|
|
// BuildMsgInitiateDomainVerification builds a MsgInitiateDomainVerification message.
|
|
func BuildMsgInitiateDomainVerification(creator, domain string) (*svctypes.MsgInitiateDomainVerification, error) {
|
|
if domain == "" {
|
|
return nil, fmt.Errorf("domain cannot be empty")
|
|
}
|
|
|
|
return &svctypes.MsgInitiateDomainVerification{
|
|
Creator: creator,
|
|
Domain: domain,
|
|
}, nil
|
|
}
|
|
|
|
// BuildMsgVerifyDomain builds a MsgVerifyDomain message.
|
|
func BuildMsgVerifyDomain(creator, domain string) (*svctypes.MsgVerifyDomain, error) {
|
|
if domain == "" {
|
|
return nil, fmt.Errorf("domain cannot be empty")
|
|
}
|
|
|
|
return &svctypes.MsgVerifyDomain{
|
|
Creator: creator,
|
|
Domain: domain,
|
|
}, nil
|
|
}
|