mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
* feat: Add Enclave Usage Examples * feat(es/ucan): Add comprehensive integration tests - Create integration.test.ts with full UCAN token lifecycle testing - Cover end-to-end token creation, parsing, and validation - Test capability attenuation and delegation chains - Validate multi-algorithm support and timestamp scenarios - Implement error recovery and performance test scenarios 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * No commit suggestions generated * No commit suggestions generated * chore: Remove migrated components and add migration documentation Removed all code and references for components that have been moved to separate repositories: **Moved to sonr-io/hway:** - bridge/ - HTTP service with OAuth2/OIDC/WebAuthn handlers - cmd/hway/ - Highway service binary - internal/migrations/ - PostgreSQL schema migrations **Moved to sonr-io/motr:** - cmd/motr/ - Motor worker service (WASM vault operations) - cmd/vault/ - Vault CLI tool - crypto/ - Comprehensive cryptographic library - packages/ - TypeScript SDK packages (es, sdk, ui, com, pkl) - web/auth/ - Authentication web application - web/dash/ - Dashboard web application **Updated Configuration:** - Makefile: Removed build/test/release targets for moved components - CLAUDE.md: Simplified to focus on core blockchain components - devbox.json: Removed scripts for moved services - docker-compose.yml: Removed hway, postgres, redis, auth, dash services - .github/scopes.yml: Removed CI scopes for migrated components - .goreleaser.yml: Updated release configuration **Added Migration Documentation:** - MIGRATE_HWAY.md: Comprehensive Highway service architecture and migration guide - MIGRATE_MOTR.md: Comprehensive Motor/Worker/Vault architecture and migration guide These migration documents provide complete context for setting up the new repositories including architecture diagrams, component breakdowns, API documentation, and migration checklists. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * No commit suggestions generated * chore: Remove contracts references and documentation Removed all references to the contracts directory that was migrated to a separate repository. **Changes:** - .gitignore: Removed contract-specific ignore patterns for DAO and wSNR contracts - .gitignore: Removed hway and motr binary references (already migrated) - .rgignore: Removed contracts, chains, and crypto directory references - docs/reference/contracts/: Removed DAO.mdx and wSNR.mdx documentation files This completes the cleanup of migrated components from the repository. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: add crypto library migration documentation Added comprehensive migration documentation for the crypto library that was moved to sonr-io/crypto repository. This documentation provides complete context for understanding the cryptographic primitives and protocols used throughout the Sonr ecosystem. ## Key Documentation Added ### MIGRATE_CRYPTO.md Complete documentation of the crypto library covering: **Core Cryptographic Primitives** - Elliptic curve implementations (Ed25519, Secp256k1, P-256, BLS12-381, Pallas/Vesta) - Native curve arithmetic with optimized field operations - Pairing-friendly curves for BLS signatures **Multi-Party Computation (MPC)** - MPC enclave for vault key generation and management - Threshold cryptography (TECDSA, TED25519 with FROST protocol) - Distributed Key Generation (DKG) via Gennaro and FROST protocols - Secret sharing schemes (Shamir, Feldman VSS, Pedersen VSS) **Digital Signature Schemes** - BLS signatures with aggregation support - BBS+ signatures for selective disclosure - Schnorr signatures (standard and Mina/NEM variants) - ECDSA with deterministic nonce generation **Zero-Knowledge Proofs** - Bulletproofs for range proofs - Inner Product Arguments (IPA) - Batch verification support **Advanced Cryptographic Protocols** - Cryptographic accumulators for set membership proofs - Paillier homomorphic encryption - Oblivious Transfer (OT) protocols - Verifiable Random Functions (VRF) **Key Management & Identity** - DID key management with multi-chain support - Multi-algorithm public key handling - Wallet address derivation (Bitcoin, Ethereum, Cosmos, Solana, etc.) **UCAN Integration** - User-Controlled Authorization Networks - Capability delegation and attenuation - JWT-based capability tokens - MPC-enabled UCAN signing **Security Utilities** - AEAD encryption (AES-GCM, AES-SIV) - Argon2 key derivation - ECIES encryption - Secure memory handling ### MIGRATE_MOTR.md Updates Updated Motor migration documentation to clarify that the crypto library is now a separate external dependency at github.com/sonr-io/crypto v1.0.1 ## Repository Context The crypto library has been successfully migrated to its own repository and is published as a Go module. It serves as the foundational cryptographic layer for: - Sonr blockchain (snrd) - DID signatures, vault operations - Highway service (hway) - UCAN token signing, WebAuthn - Motor/Worker (motr) - MPC vault operations, threshold signatures ## Integration Impact All Sonr ecosystem components now depend on the external crypto library: ```go require github.com/sonr-io/crypto v1.0.1 ``` The migration enables independent versioning and maintenance of cryptographic primitives while maintaining security and compatibility across the ecosystem. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * No commit suggestions generated * No commit suggestions generated * No commit suggestions generated --------- Co-authored-by: Claude <noreply@anthropic.com>
537 lines
15 KiB
Go
537 lines
15 KiB
Go
// Package keeper provides the DWN module keeper implementation.
|
|
package keeper
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"slices"
|
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
|
|
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
|
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
|
|
|
|
feegrantkeeper "cosmossdk.io/x/feegrant/keeper"
|
|
|
|
"cosmossdk.io/collections"
|
|
storetypes "cosmossdk.io/core/store"
|
|
"cosmossdk.io/errors"
|
|
"cosmossdk.io/log"
|
|
"cosmossdk.io/orm/model/ormdb"
|
|
|
|
apiv1 "github.com/sonr-io/sonr/api/dwn/v1"
|
|
sonrcontext "github.com/sonr-io/sonr/app/context"
|
|
"github.com/sonr-io/crypto/mpc"
|
|
"github.com/sonr-io/crypto/vrf"
|
|
"github.com/sonr-io/common/ipfs"
|
|
didtypes "github.com/sonr-io/sonr/x/did/types"
|
|
"github.com/sonr-io/sonr/x/dwn/types"
|
|
)
|
|
|
|
type Keeper struct {
|
|
cdc codec.BinaryCodec
|
|
|
|
logger log.Logger
|
|
|
|
// state management
|
|
Schema collections.Schema
|
|
Params collections.Item[types.Params]
|
|
OrmDB apiv1.StateStore
|
|
|
|
// SDK keepers for wallet operations
|
|
accountKeeper authkeeper.AccountKeeper
|
|
bankKeeper bankkeeper.Keeper
|
|
feegrantKeeper feegrantkeeper.Keeper
|
|
stakingKeeper *stakingkeeper.Keeper
|
|
didKeeper types.DIDKeeper
|
|
serviceKeeper types.ServiceKeeper
|
|
|
|
// client context for transaction building
|
|
clientCtx client.Context
|
|
|
|
// vault client for enclave operations
|
|
ipfsClient ipfs.IPFSClient
|
|
// vaultClient vault.VaultClient
|
|
|
|
// encryption subkeeper for consensus-based encryption
|
|
encryptionSubkeeper *EncryptionSubkeeper
|
|
|
|
// UCAN permission validator for DWN operations
|
|
permissionValidator *PermissionValidator
|
|
|
|
authority string
|
|
|
|
vrfPrivateKey vrf.PrivateKey
|
|
vrfPublicKey vrf.PublicKey
|
|
}
|
|
|
|
// NewKeeper creates a new Keeper instance
|
|
func NewKeeper(
|
|
cdc codec.BinaryCodec,
|
|
storeService storetypes.KVStoreService,
|
|
logger log.Logger,
|
|
authority string,
|
|
accountKeeper authkeeper.AccountKeeper,
|
|
bankKeeper bankkeeper.Keeper,
|
|
feegrantKeeper feegrantkeeper.Keeper,
|
|
stakingKeeper *stakingkeeper.Keeper,
|
|
didKeeper types.DIDKeeper,
|
|
serviceKeeper types.ServiceKeeper,
|
|
clientCtx client.Context,
|
|
) Keeper {
|
|
logger = logger.With(log.ModuleKey, "x/"+types.ModuleName)
|
|
|
|
sb := collections.NewSchemaBuilder(storeService)
|
|
|
|
if authority == "" {
|
|
authority = authtypes.NewModuleAddress(govtypes.ModuleName).String()
|
|
}
|
|
|
|
db, err := ormdb.NewModuleDB(
|
|
&types.ORMModuleSchema,
|
|
ormdb.ModuleDBOptions{KVStoreService: storeService},
|
|
)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
store, err := apiv1.NewStateStore(db)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
k := Keeper{
|
|
cdc: cdc,
|
|
logger: logger,
|
|
|
|
Params: collections.NewItem(
|
|
sb,
|
|
types.ParamsKey,
|
|
"params",
|
|
codec.CollValue[types.Params](cdc),
|
|
),
|
|
OrmDB: store,
|
|
|
|
accountKeeper: accountKeeper,
|
|
bankKeeper: bankKeeper,
|
|
feegrantKeeper: feegrantKeeper,
|
|
didKeeper: didKeeper,
|
|
stakingKeeper: stakingKeeper,
|
|
serviceKeeper: serviceKeeper,
|
|
|
|
clientCtx: clientCtx,
|
|
authority: authority,
|
|
}
|
|
|
|
schema, err := sb.Build()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
k.Schema = schema
|
|
|
|
// Load VRF keys from global context if available
|
|
if errB := k.loadVRFKeysFromContext(); errB != nil {
|
|
logger.Warn("Failed to load VRF keys from context", "error", err)
|
|
// Continue without VRF keys - they can be loaded later
|
|
}
|
|
|
|
// Initialize IPFS client
|
|
ipfsClient, err := ipfs.GetClient()
|
|
if err != nil {
|
|
logger.Error(
|
|
"Failed to initialize IPFS client",
|
|
"error",
|
|
types.ErrIPFSClientNotAvailable,
|
|
)
|
|
// Continue without IPFS client - this allows the keeper to still function
|
|
// but IPFS operations will fail gracefully
|
|
} else {
|
|
k.ipfsClient = ipfsClient
|
|
}
|
|
|
|
// Initialize encryption subkeeper
|
|
k.encryptionSubkeeper = NewEncryptionSubkeeper(&k)
|
|
|
|
// Initialize UCAN permission validator
|
|
k.permissionValidator = NewPermissionValidator(didKeeper)
|
|
|
|
return k
|
|
}
|
|
|
|
func (k Keeper) Logger() log.Logger {
|
|
return k.logger
|
|
}
|
|
|
|
// GetEncryptionSubkeeper returns the encryption subkeeper
|
|
func (k Keeper) GetEncryptionSubkeeper() *EncryptionSubkeeper {
|
|
return k.encryptionSubkeeper
|
|
}
|
|
|
|
// GetPermissionValidator returns the UCAN permission validator
|
|
func (k Keeper) GetPermissionValidator() *PermissionValidator {
|
|
return k.permissionValidator
|
|
}
|
|
|
|
// CheckAndPerformKeyRotation checks if key rotation is due and performs it if needed
|
|
func (k Keeper) CheckAndPerformKeyRotation(ctx context.Context) error {
|
|
return k.encryptionSubkeeper.CheckAndPerformRotation(ctx)
|
|
}
|
|
|
|
// ShouldEncryptRecord determines if a record should be encrypted based on protocol/schema
|
|
func (k Keeper) ShouldEncryptRecord(ctx context.Context, protocol, schema string) (bool, error) {
|
|
params, err := k.Params.Get(ctx)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
// Check if encryption is globally enabled
|
|
if !params.EncryptionEnabled {
|
|
return false, nil
|
|
}
|
|
|
|
// Check if protocol requires encryption
|
|
if slices.Contains(params.EncryptedProtocols, protocol) {
|
|
return true, nil
|
|
}
|
|
|
|
// Check if schema requires encryption
|
|
for _, encryptedSchema := range params.EncryptedSchemas {
|
|
if schema == encryptedSchema ||
|
|
(schema != "" && encryptedSchema != "" &&
|
|
len(schema) >= len(encryptedSchema) &&
|
|
schema[:len(encryptedSchema)] == encryptedSchema) {
|
|
return true, nil
|
|
}
|
|
}
|
|
|
|
return false, nil
|
|
}
|
|
|
|
// InitGenesis initializes the module's state from a genesis state.
|
|
func (k *Keeper) InitGenesis(ctx context.Context, data *types.GenesisState) error {
|
|
if err := data.Params.Validate(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := k.Params.Set(ctx, data.Params); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Import DWN records
|
|
for _, record := range data.Records {
|
|
// Convert to API type
|
|
apiRecord := &apiv1.DWNRecord{
|
|
RecordId: record.RecordId,
|
|
Target: record.Target,
|
|
Authorization: record.Authorization,
|
|
Data: record.Data,
|
|
Protocol: record.Protocol,
|
|
ProtocolPath: record.ProtocolPath,
|
|
Schema: record.Schema,
|
|
ParentId: record.ParentId,
|
|
Published: record.Published,
|
|
Attestation: record.Attestation,
|
|
Encryption: record.Encryption,
|
|
KeyDerivationScheme: record.KeyDerivationScheme,
|
|
CreatedAt: record.CreatedAt,
|
|
UpdatedAt: record.UpdatedAt,
|
|
CreatedHeight: record.CreatedHeight,
|
|
}
|
|
if record.Descriptor_ != nil {
|
|
apiRecord.Descriptor_ = &apiv1.DWNMessageDescriptor{
|
|
InterfaceName: record.Descriptor_.InterfaceName,
|
|
Method: record.Descriptor_.Method,
|
|
MessageTimestamp: record.Descriptor_.MessageTimestamp,
|
|
DataCid: record.Descriptor_.DataCid,
|
|
DataSize: record.Descriptor_.DataSize,
|
|
DataFormat: record.Descriptor_.DataFormat,
|
|
}
|
|
}
|
|
if err := k.OrmDB.DWNRecordTable().Insert(ctx, apiRecord); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Import DWN protocols
|
|
for _, protocol := range data.Protocols {
|
|
// Convert to API type
|
|
apiProtocol := &apiv1.DWNProtocol{
|
|
Target: protocol.Target,
|
|
ProtocolUri: protocol.ProtocolUri,
|
|
Definition: protocol.Definition,
|
|
Published: protocol.Published,
|
|
CreatedAt: protocol.CreatedAt,
|
|
CreatedHeight: protocol.CreatedHeight,
|
|
}
|
|
if err := k.OrmDB.DWNProtocolTable().Insert(ctx, apiProtocol); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Import DWN permissions
|
|
for _, permission := range data.Permissions {
|
|
// Convert to API type
|
|
apiPermission := &apiv1.DWNPermission{
|
|
PermissionId: permission.PermissionId,
|
|
Grantor: permission.Grantor,
|
|
Grantee: permission.Grantee,
|
|
Target: permission.Target,
|
|
InterfaceName: permission.InterfaceName,
|
|
Method: permission.Method,
|
|
Protocol: permission.Protocol,
|
|
RecordId: permission.RecordId,
|
|
Conditions: permission.Conditions,
|
|
ExpiresAt: permission.ExpiresAt,
|
|
CreatedAt: permission.CreatedAt,
|
|
Revoked: permission.Revoked,
|
|
CreatedHeight: permission.CreatedHeight,
|
|
}
|
|
if err := k.OrmDB.DWNPermissionTable().Insert(ctx, apiPermission); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Import vault states
|
|
for _, vault := range data.Vaults {
|
|
// Convert to API type
|
|
apiVault := &apiv1.VaultState{
|
|
VaultId: vault.VaultId,
|
|
Owner: vault.Owner,
|
|
PublicKey: vault.PublicKey,
|
|
CreatedAt: vault.CreatedAt,
|
|
LastRefreshed: vault.LastRefreshed,
|
|
CreatedHeight: vault.CreatedHeight,
|
|
}
|
|
if vault.EnclaveData != nil {
|
|
apiVault.EnclaveData = &apiv1.EnclaveData{
|
|
PrivateData: vault.EnclaveData.PrivateData,
|
|
PublicKey: vault.EnclaveData.PublicKey,
|
|
EnclaveId: vault.EnclaveData.EnclaveId,
|
|
Version: vault.EnclaveData.Version,
|
|
}
|
|
}
|
|
if err := k.OrmDB.VaultStateTable().Insert(ctx, apiVault); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ExportGenesis exports the module's state to a genesis state.
|
|
func (k *Keeper) ExportGenesis(ctx context.Context) *types.GenesisState {
|
|
params, err := k.Params.Get(ctx)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
genesis := &types.GenesisState{
|
|
Params: params,
|
|
Records: []types.DWNRecord{},
|
|
Protocols: []types.DWNProtocol{},
|
|
Permissions: []types.DWNPermission{},
|
|
Vaults: []types.VaultState{},
|
|
}
|
|
|
|
// Export DWN records
|
|
recordIter, err := k.OrmDB.DWNRecordTable().List(ctx, apiv1.DWNRecordPrimaryKey{})
|
|
if err == nil {
|
|
defer recordIter.Close()
|
|
for recordIter.Next() {
|
|
record, errB := recordIter.Value()
|
|
if errB == nil {
|
|
genesis.Records = append(genesis.Records, types.ConvertAPIRecordToType(record))
|
|
}
|
|
}
|
|
}
|
|
|
|
// Export DWN protocols
|
|
protocolIter, err := k.OrmDB.DWNProtocolTable().List(ctx, apiv1.DWNProtocolPrimaryKey{})
|
|
if err == nil {
|
|
defer protocolIter.Close()
|
|
for protocolIter.Next() {
|
|
protocol, errB := protocolIter.Value()
|
|
if errB == nil {
|
|
genesis.Protocols = append(
|
|
genesis.Protocols,
|
|
types.ConvertAPIProtocolToType(protocol),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Export DWN permissions
|
|
permissionIter, err := k.OrmDB.DWNPermissionTable().List(ctx, apiv1.DWNPermissionPrimaryKey{})
|
|
if err == nil {
|
|
defer permissionIter.Close()
|
|
for permissionIter.Next() {
|
|
permission, errB := permissionIter.Value()
|
|
if errB == nil {
|
|
genesis.Permissions = append(
|
|
genesis.Permissions,
|
|
types.ConvertAPIPermissionToType(permission),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Export vault states
|
|
vaultIter, err := k.OrmDB.VaultStateTable().List(ctx, apiv1.VaultStatePrimaryKey{})
|
|
if err == nil {
|
|
defer vaultIter.Close()
|
|
for vaultIter.Next() {
|
|
vault, err := vaultIter.Value()
|
|
if err == nil {
|
|
genesis.Vaults = append(genesis.Vaults, types.ConvertAPIVaultToType(vault))
|
|
}
|
|
}
|
|
}
|
|
|
|
return genesis
|
|
}
|
|
|
|
// Vault operation methods that delegate to VaultKeeper
|
|
|
|
// ValidateServiceForProtocol validates that a service is registered for a protocol operation
|
|
func (k Keeper) ValidateServiceForProtocol(ctx context.Context, target, serviceID string) error {
|
|
if serviceID == "" {
|
|
// Allow operations without explicit service registration for backward compatibility
|
|
return nil
|
|
}
|
|
|
|
// Extract domain from target (DID format: did:web:domain)
|
|
var domain string
|
|
if len(target) > 8 && target[:8] == "did:web:" {
|
|
domain = target[8:]
|
|
} else {
|
|
k.Logger().Debug("Target is not a DID:web, skipping service verification", "target", target)
|
|
return nil
|
|
}
|
|
|
|
// Verify service registration
|
|
verified, err := k.serviceKeeper.VerifyServiceRegistration(ctx, serviceID, domain)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to verify service registration")
|
|
}
|
|
|
|
if !verified {
|
|
return errors.Wrapf(
|
|
types.ErrServiceNotVerified,
|
|
"service %s not verified for domain %s",
|
|
serviceID,
|
|
domain,
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetFeeGrantKeeper returns the underlying fee grant keeper for direct access if needed.
|
|
// This method provides access to the fee grant keeper for advanced operations.
|
|
func (k Keeper) GetFeeGrantKeeper() feegrantkeeper.Keeper {
|
|
return k.feegrantKeeper
|
|
}
|
|
|
|
// loadVRFKeysFromContext loads VRF keys from the global SonrContext
|
|
func (k *Keeper) loadVRFKeysFromContext() error {
|
|
ctx := sonrcontext.GetGlobalSonrContext()
|
|
if ctx == nil {
|
|
return fmt.Errorf("global SonrContext not available")
|
|
}
|
|
|
|
if !ctx.IsInitialized() {
|
|
return fmt.Errorf("SonrContext not initialized")
|
|
}
|
|
|
|
privateKey, err := ctx.GetVRFPrivateKey()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get VRF private key from context: %w", err)
|
|
}
|
|
|
|
publicKey, err := ctx.GetVRFPublicKey()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get VRF public key from context: %w", err)
|
|
}
|
|
|
|
k.vrfPrivateKey = privateKey
|
|
k.vrfPublicKey = publicKey
|
|
|
|
k.logger.Info("VRF keys loaded from SonrContext",
|
|
"private_key_size", len(k.vrfPrivateKey),
|
|
"public_key_size", len(k.vrfPublicKey),
|
|
)
|
|
return nil
|
|
}
|
|
|
|
// GetVRFKeys returns the loaded VRF keypair
|
|
func (k Keeper) GetVRFKeys() (vrf.PrivateKey, vrf.PublicKey, error) {
|
|
if len(k.vrfPrivateKey) == 0 || len(k.vrfPublicKey) == 0 {
|
|
// Try to load from context if not already loaded
|
|
if err := k.loadVRFKeysFromContext(); err != nil {
|
|
return nil, nil, fmt.Errorf("VRF keys not loaded: %w\n"+
|
|
"To fix this issue:\n"+
|
|
" 1. Run 'snrd init <moniker>' to generate VRF keys for your node\n"+
|
|
" 2. Or disable encryption in DWN module params if not needed\n"+
|
|
" 3. For existing nodes, VRF keys should be in ~/.sonr/vrf_secret.key", err)
|
|
}
|
|
}
|
|
|
|
return k.vrfPrivateKey, k.vrfPublicKey, nil
|
|
}
|
|
|
|
// ComputeVRF generates VRF output using the keeper's loaded private key
|
|
func (k Keeper) ComputeVRF(input []byte) ([]byte, error) {
|
|
privateKey, _, err := k.GetVRFKeys()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get VRF keys: %w", err)
|
|
}
|
|
|
|
if len(input) == 0 {
|
|
return nil, fmt.Errorf("VRF input cannot be empty")
|
|
}
|
|
|
|
return privateKey.Compute(input), nil
|
|
}
|
|
|
|
// CreateVaultForDID creates a vault for a given DID using the WebAssembly enclave plugin
|
|
func (k Keeper) CreateVaultForDID(
|
|
ctx context.Context,
|
|
data *mpc.EnclaveData,
|
|
) (*didtypes.CreateVaultResponse, error) {
|
|
// Input validation
|
|
vaultState, err := k.AddEnclaveDataToIPFS(ctx, data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Insert the vault state into the database
|
|
if err := k.OrmDB.VaultStateTable().Insert(ctx, vaultState); err != nil {
|
|
k.logger.Error("Failed to store vault state",
|
|
"vault_id", vaultState.VaultId,
|
|
"error", err,
|
|
)
|
|
return nil, fmt.Errorf("failed to store vault state: %w", err)
|
|
}
|
|
|
|
// Emit typed event
|
|
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
|
event := &types.EventVaultCreated{
|
|
VaultId: vaultState.VaultId,
|
|
Owner: vaultState.Owner,
|
|
PublicKey: string(vaultState.PublicKey),
|
|
BlockHeight: uint64(sdkCtx.BlockHeight()),
|
|
}
|
|
|
|
if err := sdkCtx.EventManager().EmitTypedEvent(event); err != nil {
|
|
k.logger.With("error", err).Error("Failed to emit EventVaultCreated")
|
|
}
|
|
|
|
return &didtypes.CreateVaultResponse{}, nil
|
|
}
|