// Package dwn provides a client interface for interacting with the Sonr DWN (Decentralized Web Node) module. package dwn 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" dwntypes "github.com/sonr-io/sonr/x/dwn/types" ) // Client provides an interface for interacting with the DWN module. type Client interface { // Record Operations CreateRecord(ctx context.Context, opts *CreateRecordOptions) (*Record, error) ReadRecord(ctx context.Context, recordID string) (*Record, error) UpdateRecord(ctx context.Context, recordID string, opts *UpdateRecordOptions) (*Record, error) DeleteRecord(ctx context.Context, recordID string) error // Query Operations QueryRecords(ctx context.Context, query *RecordQuery) (*RecordQueryResponse, error) ListRecords(ctx context.Context, opts *ListRecordsOptions) (*RecordListResponse, error) // Permission Operations GrantPermission(ctx context.Context, opts *GrantPermissionOptions) (*Permission, error) RevokePermission(ctx context.Context, permissionID string) error ListPermissions(ctx context.Context, opts *ListPermissionsOptions) (*PermissionListResponse, error) // Protocol Operations InstallProtocol(ctx context.Context, protocol *Protocol) error UninstallProtocol(ctx context.Context, protocolURI string) error ListProtocols(ctx context.Context) ([]*Protocol, error) // Encryption Operations EncryptRecord(ctx context.Context, recordID string, opts *EncryptionOptions) error DecryptRecord(ctx context.Context, recordID string) (*DecryptedRecord, error) // Vault Operations CreateVault(ctx context.Context, opts *VaultOptions) (*Vault, error) ListVaults(ctx context.Context) ([]*Vault, error) ExportVault(ctx context.Context, vaultID string) (*VaultExport, error) ImportVault(ctx context.Context, vaultData *VaultExport) (*Vault, error) } // Record represents a DWN record. type Record struct { ID string `json:"id"` DID string `json:"did"` SchemaURI string `json:"schema_uri,omitempty"` ProtocolURI string `json:"protocol_uri,omitempty"` ContextID string `json:"context_id,omitempty"` ParentID string `json:"parent_id,omitempty"` Data []byte `json:"data"` Metadata map[string]any `json:"metadata,omitempty"` Encrypted bool `json:"encrypted"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at,omitempty"` Tags []string `json:"tags,omitempty"` } // CreateRecordOptions configures record creation. type CreateRecordOptions struct { DID string `json:"did"` SchemaURI string `json:"schema_uri,omitempty"` ProtocolURI string `json:"protocol_uri,omitempty"` ContextID string `json:"context_id,omitempty"` ParentID string `json:"parent_id,omitempty"` Data []byte `json:"data"` Metadata map[string]any `json:"metadata,omitempty"` Encrypt bool `json:"encrypt,omitempty"` Tags []string `json:"tags,omitempty"` } // UpdateRecordOptions configures record updates. type UpdateRecordOptions struct { Data []byte `json:"data,omitempty"` Metadata map[string]any `json:"metadata,omitempty"` Tags []string `json:"tags,omitempty"` } // RecordQuery defines query parameters for records. type RecordQuery struct { DID string `json:"did,omitempty"` SchemaURI string `json:"schema_uri,omitempty"` ProtocolURI string `json:"protocol_uri,omitempty"` ContextID string `json:"context_id,omitempty"` ParentID string `json:"parent_id,omitempty"` Tags []string `json:"tags,omitempty"` Metadata map[string]string `json:"metadata,omitempty"` DateRange *DateRange `json:"date_range,omitempty"` } // DateRange specifies a date range for queries. type DateRange struct { From string `json:"from,omitempty"` To string `json:"to,omitempty"` } // RecordQueryResponse contains query results. type RecordQueryResponse struct { Records []*Record `json:"records"` TotalCount uint64 `json:"total_count"` Limit uint64 `json:"limit"` Offset uint64 `json:"offset"` } // ListRecordsOptions configures record listing. type ListRecordsOptions struct { DID string `json:"did,omitempty"` Limit uint64 `json:"limit,omitempty"` Offset uint64 `json:"offset,omitempty"` } // RecordListResponse contains a list of records. type RecordListResponse struct { Records []*Record `json:"records"` TotalCount uint64 `json:"total_count"` Limit uint64 `json:"limit"` Offset uint64 `json:"offset"` } // Permission represents a DWN permission. type Permission struct { ID string `json:"id"` Grantor string `json:"grantor"` Grantee string `json:"grantee"` Scope string `json:"scope"` Actions []string `json:"actions"` Conditions map[string]any `json:"conditions,omitempty"` ExpiresAt string `json:"expires_at,omitempty"` CreatedAt string `json:"created_at"` } // GrantPermissionOptions configures permission granting. type GrantPermissionOptions struct { Grantee string `json:"grantee"` Scope string `json:"scope"` Actions []string `json:"actions"` Conditions map[string]any `json:"conditions,omitempty"` ExpiresAt string `json:"expires_at,omitempty"` } // ListPermissionsOptions configures permission listing. type ListPermissionsOptions struct { Grantee string `json:"grantee,omitempty"` Scope string `json:"scope,omitempty"` Limit uint64 `json:"limit,omitempty"` Offset uint64 `json:"offset,omitempty"` } // PermissionListResponse contains a list of permissions. type PermissionListResponse struct { Permissions []*Permission `json:"permissions"` TotalCount uint64 `json:"total_count"` Limit uint64 `json:"limit"` Offset uint64 `json:"offset"` } // Protocol represents a DWN protocol. type Protocol struct { URI string `json:"uri"` Name string `json:"name"` Version string `json:"version"` Description string `json:"description,omitempty"` Schema map[string]any `json:"schema"` Rules map[string]any `json:"rules,omitempty"` CreatedAt string `json:"created_at"` } // EncryptionOptions configures record encryption. type EncryptionOptions struct { Algorithm string `json:"algorithm,omitempty"` Recipients []string `json:"recipients,omitempty"` KeyDerivation map[string]any `json:"key_derivation,omitempty"` } // DecryptedRecord contains decrypted record data. type DecryptedRecord struct { Record *Record `json:"record"` Data []byte `json:"data"` Algorithm string `json:"algorithm"` } // Vault represents a DWN vault. type Vault struct { ID string `json:"id"` DID string `json:"did"` Name string `json:"name"` Type string `json:"type"` Config map[string]any `json:"config"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at,omitempty"` } // VaultOptions configures vault creation. type VaultOptions struct { DID string `json:"did"` Name string `json:"name"` Type string `json:"type,omitempty"` Config map[string]any `json:"config,omitempty"` } // VaultExport contains exported vault data. type VaultExport struct { Vault *Vault `json:"vault"` Records []*Record `json:"records"` Protocols []*Protocol `json:"protocols"` Metadata map[string]any `json:"metadata"` } // client implements the DWN Client interface. type client struct { grpcConn *grpc.ClientConn config *config.NetworkConfig // Service clients for DWN module queryClient dwntypes.QueryClient msgClient dwntypes.MsgClient txClient tx.ServiceClient } // NewClient creates a new DWN module client. func NewClient(grpcConn *grpc.ClientConn, cfg *config.NetworkConfig) Client { return &client{ grpcConn: grpcConn, config: cfg, queryClient: dwntypes.NewQueryClient(grpcConn), msgClient: dwntypes.NewMsgClient(grpcConn), txClient: tx.NewServiceClient(grpcConn), } } // CreateRecord creates a new record in the DWN. func (c *client) CreateRecord(ctx context.Context, opts *CreateRecordOptions) (*Record, error) { // TODO: Implement record creation using DWN module // Should build MsgRecordsWrite with proper descriptor // Validate record data size and format // Handle encryption if requested in options // Submit transaction and return created record with ID return nil, errors.NewModuleError("dwn", "CreateRecord", fmt.Errorf("record creation not yet implemented")) } // ReadRecord retrieves a record by ID. func (c *client) ReadRecord(ctx context.Context, recordID string) (*Record, error) { // TODO: Implement record reading using DWN module query client // Should query chain state for record by ID // Check read permissions and UCAN authorization // Decrypt record data if encrypted // Return complete record with metadata return nil, errors.NewModuleError("dwn", "ReadRecord", fmt.Errorf("record reading not yet implemented")) } // UpdateRecord updates an existing record. func (c *client) UpdateRecord(ctx context.Context, recordID string, opts *UpdateRecordOptions) (*Record, error) { // TODO: Implement record updates using DWN module // Should validate record ownership and update permissions // Build MsgRecordsWrite with updated data // Preserve original record metadata unless modified // Handle encryption for updated data return nil, errors.NewModuleError("dwn", "UpdateRecord", fmt.Errorf("record updates not yet implemented")) } // DeleteRecord deletes a record. func (c *client) DeleteRecord(ctx context.Context, recordID string) error { // TODO: Implement record deletion using DWN module // Should validate record ownership and delete permissions // Build MsgRecordsDelete and submit to chain // Handle soft delete vs hard delete based on protocol // Clean up associated IPFS data if applicable return errors.NewModuleError("dwn", "DeleteRecord", fmt.Errorf("record deletion not yet implemented")) } // QueryRecords queries records based on specified criteria. func (c *client) QueryRecords(ctx context.Context, query *RecordQuery) (*RecordQueryResponse, error) { // TODO: Implement record querying using DWN module // Should support complex queries with multiple filters // Filter by DID, schema, protocol, context, parent // Support date range and tag-based filtering // Return paginated results with total count return nil, errors.NewModuleError("dwn", "QueryRecords", fmt.Errorf("record querying not yet implemented")) } // ListRecords lists records with pagination. func (c *client) ListRecords(ctx context.Context, opts *ListRecordsOptions) (*RecordListResponse, error) { // TODO: Implement record listing using DWN module // Should support pagination with limit/offset // Filter by DID if specified // Return records with basic metadata // Handle empty result sets gracefully return nil, errors.NewModuleError("dwn", "ListRecords", fmt.Errorf("record listing not yet implemented")) } // GrantPermission grants a permission to access records. func (c *client) GrantPermission(ctx context.Context, opts *GrantPermissionOptions) (*Permission, error) { // TODO: Implement permission granting using DWN module // Should build MsgPermissionsGrant with proper conditions // Validate grantee DID and permission scope // Set expiration and action restrictions // Return permission record with unique ID return nil, errors.NewModuleError("dwn", "GrantPermission", fmt.Errorf("permission granting not yet implemented")) } // RevokePermission revokes a previously granted permission. func (c *client) RevokePermission(ctx context.Context, permissionID string) error { // TODO: Implement permission revocation using DWN module // Should build MsgPermissionsRevoke and submit to chain // Validate permission ownership before revocation // Update permission status to revoked // Notify affected systems of permission changes return errors.NewModuleError("dwn", "RevokePermission", fmt.Errorf("permission revocation not yet implemented")) } // ListPermissions lists permissions with optional filtering. func (c *client) ListPermissions(ctx context.Context, opts *ListPermissionsOptions) (*PermissionListResponse, error) { // TODO: Implement permission listing using DWN module // Should support filtering by grantee, scope, status // Include permission expiration and condition info // Support pagination with limit/offset // Return permissions with grant metadata return nil, errors.NewModuleError("dwn", "ListPermissions", fmt.Errorf("permission listing not yet implemented")) } // InstallProtocol installs a new protocol. func (c *client) InstallProtocol(ctx context.Context, protocol *Protocol) error { // TODO: Implement protocol installation using DWN module // Should build MsgProtocolsConfigure and submit to chain // Validate protocol schema and rules format // Check protocol URI uniqueness and versioning // Store protocol definition for record validation return errors.NewModuleError("dwn", "InstallProtocol", fmt.Errorf("protocol installation not yet implemented")) } // UninstallProtocol uninstalls a protocol. func (c *client) UninstallProtocol(ctx context.Context, protocolURI string) error { // TODO: Implement protocol uninstallation using DWN module // Should check for existing records using this protocol // Prevent uninstallation if records depend on protocol // Remove protocol definition from storage // Handle graceful protocol deprecation return errors.NewModuleError("dwn", "UninstallProtocol", fmt.Errorf("protocol uninstallation not yet implemented")) } // ListProtocols lists installed protocols. func (c *client) ListProtocols(ctx context.Context) ([]*Protocol, error) { // TODO: Implement protocol listing using DWN module // Should query chain state for installed protocols // Return protocols with schema, rules, and version info // Include protocol usage statistics if available // Handle empty protocol list gracefully return nil, errors.NewModuleError("dwn", "ListProtocols", fmt.Errorf("protocol listing not yet implemented")) } // EncryptRecord encrypts a record. func (c *client) EncryptRecord(ctx context.Context, recordID string, opts *EncryptionOptions) error { // TODO: Implement record encryption using DWN module // Should validate record ownership and encryption options // Use AES-GCM with secure key derivation from recipients // Store encrypted data with authentication tag // Update record metadata to mark as encrypted return errors.NewModuleError("dwn", "EncryptRecord", fmt.Errorf("record encryption not yet implemented")) } // DecryptRecord decrypts a record. func (c *client) DecryptRecord(ctx context.Context, recordID string) (*DecryptedRecord, error) { // TODO: Implement record decryption using DWN module // Should validate decryption permissions and key access // Use stored encryption algorithm and key derivation // Verify authentication tag before returning data // Return decrypted record with original format info return nil, errors.NewModuleError("dwn", "DecryptRecord", fmt.Errorf("record decryption not yet implemented")) } // CreateVault creates a new vault. func (c *client) CreateVault(ctx context.Context, opts *VaultOptions) (*Vault, error) { // TODO: Implement vault creation using DWN module and Motor plugin // Should validate DID ownership and vault configuration // Use Motor WASM enclave for secure vault initialization // Generate vault keys using hardware-backed security // Store vault metadata on chain with IPFS references return nil, errors.NewModuleError("dwn", "CreateVault", fmt.Errorf("vault creation not yet implemented")) } // ListVaults lists available vaults. func (c *client) ListVaults(ctx context.Context) ([]*Vault, error) { // TODO: Implement vault listing using DWN module // Should query chain state for user vaults // Return vaults with metadata and configuration // Include vault status and last update information // Handle access permissions for vault visibility return nil, errors.NewModuleError("dwn", "ListVaults", fmt.Errorf("vault listing not yet implemented")) } // ExportVault exports vault data. func (c *client) ExportVault(ctx context.Context, vaultID string) (*VaultExport, error) { // TODO: Implement vault export using DWN module and Motor plugin // Should validate vault ownership and export permissions // Use Motor plugin to securely export vault contents // Include all records, protocols, and permissions // Encrypt export data for secure transfer return nil, errors.NewModuleError("dwn", "ExportVault", fmt.Errorf("vault export not yet implemented")) } // ImportVault imports vault data. func (c *client) ImportVault(ctx context.Context, vaultData *VaultExport) (*Vault, error) { // TODO: Implement vault import using DWN module and Motor plugin // Should validate import data integrity and format // Use Motor plugin to securely import vault contents // Restore records, protocols, and permissions // Handle conflicts with existing data gracefully return nil, errors.NewModuleError("dwn", "ImportVault", fmt.Errorf("vault import not yet implemented")) } // Utility functions // GenerateRecordID generates a unique record ID. func GenerateRecordID() string { // TODO: Implement proper record ID generation return fmt.Sprintf("record_%d", time.Now().UnixNano()) } // ValidateRecordData validates record data. func ValidateRecordData(data []byte) error { if len(data) == 0 { return fmt.Errorf("record data cannot be empty") } // Add size limits and other validation as needed if len(data) > 10*1024*1024 { // 10MB limit return fmt.Errorf("record data too large") } return nil } // CreateDefaultProtocol creates a default protocol configuration. func CreateDefaultProtocol(name, version string) *Protocol { return &Protocol{ URI: fmt.Sprintf("https://protocols.sonr.io/%s/%s", name, version), Name: name, Version: version, Description: fmt.Sprintf("Default protocol for %s", name), Schema: map[string]any{}, Rules: map[string]any{}, } } // Message Builders - These create the actual transaction messages // BuildMsgRecordsWrite builds a MsgRecordsWrite message. func BuildMsgRecordsWrite(author, target string, opts *CreateRecordOptions) (*dwntypes.MsgRecordsWrite, error) { if opts == nil { return nil, fmt.Errorf("options cannot be nil") } // Create message descriptor descriptor := &dwntypes.DWNMessageDescriptor{ InterfaceName: "Records", Method: "Write", MessageTimestamp: time.Now().Format(time.RFC3339), DataFormat: "application/json", // Default format DataSize: int64(len(opts.Data)), } return &dwntypes.MsgRecordsWrite{ Author: author, Target: target, Descriptor_: descriptor, Authorization: "", // Will be set by the transaction builder Data: opts.Data, }, nil } // BuildMsgRecordsDelete builds a MsgRecordsDelete message. func BuildMsgRecordsDelete(author, target, recordID string) (*dwntypes.MsgRecordsDelete, error) { if recordID == "" { return nil, fmt.Errorf("record ID cannot be empty") } // Create message descriptor descriptor := &dwntypes.DWNMessageDescriptor{ InterfaceName: "Records", Method: "Delete", MessageTimestamp: time.Now().Format(time.RFC3339), } return &dwntypes.MsgRecordsDelete{ Author: author, Target: target, RecordId: recordID, Descriptor_: descriptor, Authorization: "", // Will be set by the transaction builder }, nil } // BuildMsgProtocolsConfigure builds a MsgProtocolsConfigure message. func BuildMsgProtocolsConfigure(author, target string, protocol *Protocol) (*dwntypes.MsgProtocolsConfigure, error) { if protocol == nil { return nil, fmt.Errorf("protocol cannot be nil") } // Create message descriptor descriptor := &dwntypes.DWNMessageDescriptor{ InterfaceName: "Protocols", Method: "Configure", MessageTimestamp: time.Now().Format(time.RFC3339), } // Note: The actual protocol definition would need to be serialized // This is a placeholder implementation return &dwntypes.MsgProtocolsConfigure{ Author: author, Target: target, Descriptor_: descriptor, Authorization: "", // Will be set by the transaction builder // Definition would be set here based on the protocol }, nil } // BuildMsgPermissionsGrant builds a MsgPermissionsGrant message. func BuildMsgPermissionsGrant(grantor, grantee, target string, grant *GrantPermissionOptions) (*dwntypes.MsgPermissionsGrant, error) { if grant == nil { return nil, fmt.Errorf("permission grant cannot be nil") } // Create message descriptor descriptor := &dwntypes.DWNMessageDescriptor{ InterfaceName: "Permissions", Method: "Grant", MessageTimestamp: time.Now().Format(time.RFC3339), } // Note: The actual permission grant would need to be serialized // This is a placeholder implementation return &dwntypes.MsgPermissionsGrant{ Grantor: grantor, Grantee: grantee, Target: target, Descriptor_: descriptor, Authorization: "", // Will be set by the transaction builder // PermissionGrant would be set here }, nil } // BuildMsgPermissionsRevoke builds a MsgPermissionsRevoke message. func BuildMsgPermissionsRevoke(grantor, permissionID string) (*dwntypes.MsgPermissionsRevoke, error) { if permissionID == "" { return nil, fmt.Errorf("permission ID cannot be empty") } // Create message descriptor descriptor := &dwntypes.DWNMessageDescriptor{ InterfaceName: "Permissions", Method: "Revoke", MessageTimestamp: time.Now().Format(time.RFC3339), } return &dwntypes.MsgPermissionsRevoke{ Grantor: grantor, PermissionId: permissionID, Descriptor_: descriptor, Authorization: "", // Will be set by the transaction builder }, nil } // BuildMsgRotateVaultKeys builds a MsgRotateVaultKeys message. func BuildMsgRotateVaultKeys(authority, vaultID string) *dwntypes.MsgRotateVaultKeys { return &dwntypes.MsgRotateVaultKeys{ Authority: authority, VaultId: vaultID, } }