# Identity & KYC

Technical overview of how KYC/KYB verification is bound to user principals on the Internet Computer.


# Identity Binding

Tortuga uses Sumsub for identity verification. Once verified, the KYC status is bound to a principal on the Internet Computer.

flowchart TB
    USER[User] --> SUMSUB[Sumsub Verification]
    SUMSUB --> RESULT{Approved?}
    RESULT -->|Yes| BIND[Bind to Principal]
    RESULT -->|No| REJECT[Rejected]

    BIND --> OPT1[New Principal]
    BIND --> OPT2[Internet Identity]

# Binding Options

# Option 1: New Principal

A new cryptographic principal is created specifically for the user.

sequenceDiagram
    participant User
    participant Sumsub
    participant Backend as Tortuga Backend
    participant Registry as KYC Registry

    User->>Sumsub: Complete Verification
    Sumsub-->>Backend: Webhook (Approved)
    Backend->>Backend: Generate New Principal
    Backend->>Registry: Store (Principal, KYC Status)
    Backend-->>User: Principal + Seed Phrase
Pros Cons
Simple onboarding New wallet to manage
Dedicated identity Not portable to other ICP apps

# Option 2: Internet Identity

KYC status is bound to the user's existing Internet Identity.

sequenceDiagram
    participant User
    participant II as Internet Identity
    participant Sumsub
    participant Backend as Tortuga Backend
    participant Registry as KYC Registry

    User->>II: Authenticate
    II-->>Backend: Principal
    Backend->>Sumsub: Start KYC (with Principal ref)
    User->>Sumsub: Complete Verification
    Sumsub-->>Backend: Webhook (Approved)
    Backend->>Registry: Store (II Principal, KYC Status)
Pros Cons
Use existing identity Requires II account
Portable across ICP ecosystem Slightly more complex flow

# KYC Registry Canister

The KYC Registry is a canister on ICP that stores verification status.

flowchart LR
    subgraph KYC Registry
        MAP[Principal → Status]
        LEVEL[Verification Level]
        EXPIRY[Expiration]
    end

    ML[Master Ledger] --> MAP
    ML --> LEVEL

# Data Model

type KycStatus = variant {
    Pending;
    Verified : KycData;
    Rejected;
    Expired;
};

type KycData = record {
    level : KycLevel;
    verified_at : Timestamp;
    expires_at : opt Timestamp;
    provider_ref : Text;  // Sumsub reference
};

type KycLevel = variant {
    Basic;      // Individual KYC
    Enhanced;   // Enhanced due diligence
    Corporate;  // KYB for entities
};

# Registry Interface

service : {
    // Query KYC status
    get_status : (Principal) -> (opt KycStatus) query;

    // Check if principal is verified (used by Master Ledger)
    is_verified : (Principal) -> (bool) query;

    // Called by backend after Sumsub webhook
    set_verified : (Principal, KycData) -> (Result);

    // Revoke verification
    revoke : (Principal) -> (Result);
}

# Integration with Master Ledger

The Master Ledger queries the KYC Registry before allowing operations.

flowchart TB
    REQ[Transfer Request] --> ML[Master Ledger]
    ML --> CHECK[Query KYC Registry]
    CHECK --> STATUS{Both Verified?}
    STATUS -->|Yes| EXEC[Execute Transfer]
    STATUS -->|No| DENY[Deny Transfer]

All token operations (mint, transfer, burn) require:

  1. Caller principal is verified
  2. Recipient principal is verified (for transfers)
  3. Verification has not expired