SolanaSolana support coming soon. dWallets are expanding to Solana for native cross-chain signing.
Ika LogoIka Docs
Core Concepts

Capabilities and Approvals

Ika uses a capability-based authorization system to control access to dWallet operations. Understanding these capabilities is essential for building secure Move contracts.

Overview

Capabilities are objects that grant specific permissions:

CapabilityPurposeCreated By
DWalletCapAuthorize signing for a dWalletDKG protocol
ImportedKeyDWalletCapAuthorize signing for imported key dWalletImport verification
UnverifiedPresignCapReference to a presign (needs verification)Presign request
VerifiedPresignCapVerified presign ready for signingPresign verification
UnverifiedPartialUserSignatureCapPartial signature (needs verification)Future sign request
VerifiedPartialUserSignatureCapVerified partial signaturePartial signature verification
MessageApprovalAuthorization to sign a specific messageapprove_message()
ImportedKeyMessageApprovalMessage approval for imported keysapprove_imported_key_message()

DWalletCap

The DWalletCap is the primary authorization capability for a dWallet. It's created during DKG and must be stored securely.

Storage Pattern

public struct MyContract has key, store {
    id: UID,
    dwallet_cap: DWalletCap,  // Store the capability
    // ...
}

Usage

// Use DWalletCap to approve messages
let message_approval = coordinator.approve_message(
    &self.dwallet_cap,
    signature_algorithm,
    hash_scheme,
    message,
);

Key Properties

// Get the dWallet ID from the capability
let dwallet_id: ID = dwallet_cap.dwallet_id();

Security

The DWalletCap controls who can sign with your dWallet. Never expose it outside your contract without proper access controls.

ImportedKeyDWalletCap

Similar to DWalletCap but for dWallets created by importing existing private keys.

public struct MyContract has key, store {
    id: UID,
    imported_dwallet_cap: ImportedKeyDWalletCap,
    // ...
}
 
// Approve message for imported key dWallet
let approval = coordinator.approve_imported_key_message(
    &self.imported_dwallet_cap,
    signature_algorithm,
    hash_scheme,
    message,
);

Presign Capabilities

Presigns go through a verification lifecycle:

Presign Lifecycle

1. REQUEST
request_global_presign() or request_presign()
UnverifiedPresignCap
(store in pool)
2. VERIFY
Network processes presign (async)
VerifiedPresignCap
(ready for signing)
3. CONSUME
Presign is destroyed during signing

Storing Unverified Presigns

public struct MyContract has key, store {
    id: UID,
    presigns: vector<UnverifiedPresignCap>,  // Pool of presigns
    // ...
}
 
// Request and store presign
let unverified_cap = coordinator.request_global_presign(
    network_encryption_key_id,
    curve,
    signature_algorithm,
    session_identifier,
    &mut payment_ika,
    &mut payment_sui,
    ctx,
);
self.presigns.push_back(unverified_cap);

Verifying Before Use

// Pop from pool and verify
let unverified_cap = self.presigns.swap_remove(0);
let verified_cap = coordinator.verify_presign_cap(unverified_cap, ctx);
 
// Use verified cap for signing
coordinator.request_sign(
    verified_cap,  // Consumed here
    message_approval,
    message_centralized_signature,
    session_identifier,
    &mut payment_ika,
    &mut payment_sui,
    ctx,
);

Checking Validity

// Check if presign is ready (network has completed it)
let is_valid = coordinator.is_presign_valid(&unverified_cap);

Partial User Signature Capabilities

For two-phase (future) signing:

Two-Phase Process

PHASE 1: COMMIT
User creates partial signature and stores it
request_future_sign()
UnverifiedPartialUserSignatureCap
(store with request)
Governance / Approval Process
Network verifies partial signature
PHASE 2: EXECUTE
After approval, complete the signature
verify_partial_user_signature_cap()
approve_message()
request_sign_with_partial_user_signature()

Storage Pattern for Governance

public struct Request has store {
    id: u64,
    message: vector<u8>,
    partial_sig_cap: Option<UnverifiedPartialUserSignatureCap>,
    votes: Table<address, bool>,
}
 
// Store partial signature with request
let partial_cap = coordinator.request_future_sign(
    dwallet_id,
    verified_presign_cap,
    message,
    hash_scheme,
    message_centralized_signature,
    session_identifier,
    &mut payment_ika,
    &mut payment_sui,
    ctx,
);
 
let request = Request {
    id: next_id,
    message,
    partial_sig_cap: option::some(partial_cap),
    votes: table::new(ctx),
};

Completing the Signature

// Extract and verify partial signature cap
let partial_cap = request.partial_sig_cap.extract();
let verified_partial = coordinator.verify_partial_user_signature_cap(partial_cap, ctx);
 
// Create message approval
let approval = coordinator.approve_message(
    &self.dwallet_cap,
    signature_algorithm,
    hash_scheme,
    request.message,
);
 
// Complete the signature
let sign_id = coordinator.request_sign_with_partial_user_signature_and_return_id(
    verified_partial,
    approval,
    session_identifier,
    &mut payment_ika,
    &mut payment_sui,
    ctx,
);

Message Approvals

Message approvals are created just before signing and authorize signing a specific message.

Creating Approvals

// For standard dWallets
let approval = coordinator.approve_message(
    &dwallet_cap,
    signature_algorithm,  // e.g., 1 for Taproot
    hash_scheme,          // e.g., 0 for SHA256
    message,              // The message bytes to sign
);
 
// For imported key dWallets
let approval = coordinator.approve_imported_key_message(
    &imported_dwallet_cap,
    signature_algorithm,
    hash_scheme,
    message,
);

Matching with Partial Signatures

For future signing, you can verify that a partial signature matches a message approval:

let matches = coordinator.match_partial_user_signature_with_message_approval(
    &verified_partial_cap,
    &message_approval,
);
assert!(matches, EPartialSignatureDoesNotMatch);

Capability Lifecycle Summary

Capability Lifecycle Summary

DKG
request_dwallet_dkg() → DWalletCap
(store permanently)
Presigning
request_presign()
→ UnverifiedPresignCap (pool)
verify_presign_cap()
→ VerifiedPresignCap (use once)
Signing
approve_message()
→ MessageApproval
request_sign()
consumes caps
Future Signing
request_future_sign()
→ UnverifiedPartialUserSignatureCap
request_sign_with_partial...
completes signing

Next Steps