> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cultura.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Verification & Attestation Flow (Levels 0-2)

This flow details how a digital asset progresses from its initial minted state (Level 0) to becoming attested (Level 1) and finally achieving Verified Rights (Level 2), making it licensable within the Cultura Proof of Rights Protocol.

## Flow Diagram

```mermaid theme={null}
sequenceDiagram
    participant Owner
    participant Dapp
    participant SDK_Owner as SDK (Owner)
    participant SchemaRegistry
    participant BondTokenContract
    participant CASContract
    participant Verifier
    participant SDK_Verifier as SDK (Verifier)
    participant RightsBoundAccount

    Owner->>Dapp: Initiate Attestation (L0 -> L1)
    Dapp->>SDK_Owner: attest(assetInfo, grade, bondAmount)
    activate SDK_Owner

    %% Schema Handling (Implicit or Explicit)
    SDK_Owner->>SchemaRegistry: getOrRegisterSchema(schema)
    SchemaRegistry-->>SDK_Owner: schemaUID

    %% Bond Token Approval
    SDK_Owner->>BondTokenContract: approve(CASContract, bondAmount)
    BondTokenContract-->>SDK_Owner: Approval Success

    %% Attestation Call
    SDK_Owner->>CASContract: attest(requestData, assetAddress, assetId, grade, bondAmount)
    activate CASContract
    CASContract->>BondTokenContract: transferFrom(Owner, CASContract, bondAmount)
    CASContract->>RightsBoundAccount: deploy()
    RightsBoundAccount-->>CASContract: RBA Address
    CASContract-->>SDK_Owner: Attestation UID, RBA Address (via Event)
    deactivate CASContract
    SDK_Owner-->>Dapp: Attestation Success (Asset is Level 1)
    deactivate SDK_Owner
    Dapp-->>Owner: Attestation Complete

    Note over Owner, Verifier: Asset is now Level 1 (Attested)

    Verifier->>Dapp: Initiate Verification (L1 -> L2)
    Dapp->>SDK_Verifier: verifyAttestation(attestationUID, verificationBond)
    activate SDK_Verifier

    %% Bond Token Approval for Verification
    SDK_Verifier->>BondTokenContract: approve(CASContract, verificationBond)
    BondTokenContract-->>SDK_Verifier: Approval Success

    %% Verification Call
    SDK_Verifier->>CASContract: verifyAttestation(attestationUID, verificationBond)
    activate CASContract
    CASContract->>BondTokenContract: transferFrom(Verifier, CASContract, verificationBond)
    CASContract->>CASContract: Check Level Promotion Thresholds
    alt Thresholds Met
        CASContract->>CASContract: Update Asset Level to 2
        CASContract-->>SDK_Verifier: Verification Success (Level 2 Achieved)
    else Thresholds Not Met
        CASContract-->>SDK_Verifier: Verification Success (Level Remains 1)
    end
    deactivate CASContract
    SDK_Verifier-->>Dapp: Verification Result
    deactivate SDK_Verifier
    Dapp-->>Verifier: Verification Complete

    Note over Owner, Verifier: Asset is now Level 2 (Verified Rights / Licensable) if thresholds were met.
```

## Explanation

### Part 1: Attestation (Level 0 -> Level 1)

1. **Owner Initiates:** The owner of a minted digital asset (Level 0) uses a dApp to start the attestation process.
2. **Schema Handling (SDK):** The SDK ensures the correct schema exists by calling `sdk.schemaRegistry.getOrRegisterSchema()`. This returns a `schemaUID`. This step is crucial for defining the structure of the attestation data.
3. **Bond Token Approval (SDK):** The SDK prompts the owner's wallet to approve the `CASContract` to spend the required `bondAmount` (determined by the chosen Grade) of the designated bond token. This calls `sdk.bondToken.approve()`. Approval must be granted before the `attest` call.
4. **Attestation Call (SDK):** The SDK calls `sdk.attestationService.attest()`, providing:
   * `attestationRequest`: Contains the `schemaUID`, recipient (usually the owner), expiration time (0 for non-expiring), revocability flag, and any specific attestation data encoded according to the schema.
   * `digitalAssetAddress`: The contract address of the asset being attested.
   * `digitalAssetId`: The token ID of the asset.
   * `grade`: The numerical grade (0-3) chosen by the owner, influencing bond requirements and Level 2 thresholds.
   * `bondAmount`: The amount of bond tokens required for the chosen grade's fee.
5. **Contract Execution (CAS):**
   * The `CASContract` verifies the inputs (schema exists, grade is valid, etc.).
   * It transfers the `bondAmount` from the owner to itself using the prior approval.
   * It deploys a new `RightsBoundAccount` contract specifically for this asset's attestation, linking the asset to its future royalty and rights management.
   * It stores the attestation details (UID, schema, recipient, attester, times, data, asset link, RBA link).
   * It updates the asset's level to 1 (`digitalAssetLevels` mapping).
   * It emits an `Attested` event (containing the `attestationUID`) and a `CulturaRightsBoundAccountDeployed` event (containing the RBA address).
6. **Result (SDK/Dapp):** The SDK parses the events from the transaction receipt using `getAttestationDataFromReceipt` to extract the `attestationUID` and the `rightsBoundAccount` address, returning them to the dApp. The asset is now **Level 1 (Attested)**.

### Part 2: Verification (Level 1 -> Level 2)

1. **Verifier Initiates:** A community member or whitelisted verifier uses a dApp to verify/endorse an existing Level 1 attestation, identified by its `attestationUID`.
2. **Bond Token Approval (SDK):** The SDK prompts the verifier's wallet to approve the `CASContract` to spend the `verificationBond` amount they wish to contribute. This calls `sdk.bondToken.approve()`.
3. **Verification Call (SDK):** The SDK calls `sdk.attestationService.verifyAttestation()`, providing the `attestationUID` and the `verificationBond` amount.
4. **Contract Execution (CAS):**
   * The `CASContract` verifies the attestation exists and is currently Level 1.
   * It transfers the `verificationBond` from the verifier to itself.
   * It records the verification details, linking the verifier and their bonded amount to the attestation (`verifierCount`, `communityUserCount`, `WLVerifierCount`, `bondedAmount` on the Attestation struct are updated).
   * It **checks if the promotion thresholds** (total bonded tokens OR number/type of unique verifiers) defined by the asset's [Grade](../smart-contracts-reference/concepts#grades) have now been met by calling the internal `_checkVerifiedVerifiedLevel` function.
   * **If thresholds are met:** The contract updates the asset's level to 2 (`digitalAssetLevels` mapping) via `_promoteDigitalAsset`.
   * It emits a `Verified` event.
5. **Result (SDK/Dapp):** The SDK returns the transaction result. If the thresholds were met during this verification, the asset is now **Level 2 (Verified Rights)** and is considered licensable through integrated protocols.

## SDK Snippets

```typescript theme={null}
import { CulturaSDK } from "@cultura/sdk";
import { parseEther } from "viem"; // Example utility

/**
 * Attests an asset, moving it from Level 0 to Level 1.
 * Assumes the SDK is initialized for the ASSET OWNER.
 */
async function attestAsset(
  sdk: CulturaSDK,
  recipientAddress: `0x${string}`, // Usually the owner's address
  assetAddress: `0x${string}`,
  assetId: bigint,
  grade: bigint, // e.g., 3n for Grade C
  bondAmount: bigint // e.g., parseEther("0.0001") for Grade C bond fee
) {
  try {
    // --- 1. Ensure Schema Exists ---
    // Define the schema string used for your attestations
    const schemaStr =
      "string digitalAssetName, string digitalAssetDescription, uint256 grade"; // Example
    const isRevocable = true; // Or false, depending on your use case
    const schemaUID = await sdk.schemaRegistry.getOrRegisterSchema(
      schemaStr,
      isRevocable
    );
    console.log("Using Schema UID:", schemaUID);

    // --- 2. Approve Bond Token Spending ---
    const casAddress = sdk.config.contracts?.attestationService;
    if (!casAddress) throw new Error("CAS address not configured in SDK");

    console.log(
      `Approving ${bondAmount.toString()} bond tokens for CAS (${casAddress})...`
    );
    // Ensure the owner has sufficient bond tokens before approving
    const approveTxHash = await sdk.bondToken.approve(casAddress, bondAmount);
    console.log("Bond Token Approval Tx:", approveTxHash);
    // It's crucial to wait for this transaction to be mined before proceeding
    await sdk.publicClient.waitForTransactionReceipt({ hash: approveTxHash });
    console.log("Approval confirmed.");

    // --- 3. Prepare Attestation Request ---
    // Encode data according to your schema if necessary. For the example schema,
    // you might encode the asset name, description, and grade again here,
    // or leave data as '0x' if the core info is implicitly linked via assetId.
    const encodedData = "0x" as `0x${string}`; // Placeholder

    const attestationRequest = {
      schema: schemaUID,
      data: {
        recipient: recipientAddress,
        expirationTime: 0n, // 0 for non-expiring attestations
        revocable: isRevocable,
        refUID:
          "0x0000000000000000000000000000000000000000000000000000000000000000" as `0x${string}`, // Use if referencing another attestation
        data: encodedData,
      },
    };

    // --- 4. Call Attest ---
    console.log("Submitting attestation to CAS...");
    // The attest method waits for the transaction and returns the UID directly
    const attestationUid = await sdk.attestationService.attest(
      attestationRequest,
      assetAddress,
      assetId,
      grade,
      bondAmount // This is the fee/initial bond required by the grade
    );
    console.log(`Attestation Successful! UID: ${attestationUid}`);
    console.log(`Asset is now Level 1 (Attested)`);

    // Note: The RightsBoundAccount is deployed automatically during attest.
    // You can query for it later using the attestation UID or asset details if needed.
    // For simplicity, we're not retrieving it explicitly here.

    return { attestationUid }; // Return only the UID for this example
  } catch (error) {
    console.error("Error during attestation:", error);
    throw error; // Re-throw for higher-level handling
  }
}

/**
 * Verifies an existing Level 1 attestation, potentially promoting it to Level 2.
 * Assumes the SDK is initialized for the VERIFIER.
 */
async function verifyAssetAttestation(
  sdk: CulturaSDK, // SDK instance initialized for the VERIFIER
  attestationUID: `0x${string}`,
  verificationBond: bigint // Amount the verifier wants to bond, e.g., parseEther("0.01")
) {
  try {
    // --- 1. Approve Bond Token Spending ---
    const casAddress = sdk.config.contracts?.attestationService;
    if (!casAddress) throw new Error("CAS address not configured in SDK");

    console.log(
      `Approving ${verificationBond.toString()} tokens for CAS (${casAddress})...`
    );
    // Ensure the verifier has sufficient bond tokens
    const approveTxHash = await sdk.bondToken.approve(
      casAddress,
      verificationBond
    );
    console.log("Approval Tx:", approveTxHash);
    await sdk.publicClient.waitForTransactionReceipt({ hash: approveTxHash });
    console.log("Approval confirmed.");

    // --- 2. Call Verify Attestation ---
    console.log(`Verifying attestation ${attestationUID}...`);
    const verifyTxHash = await sdk.attestationService.verifyAttestation(
      attestationUID,
      verificationBond
    );
    console.log("Verify Tx:", verifyTxHash);

    const receipt = await sdk.publicClient.waitForTransactionReceipt({
      hash: verifyTxHash,
    });
    if (receipt.status !== "success") {
      throw new Error("Verification transaction failed");
    }

    console.log(`Verification submitted successfully.`);

    // --- 3. Check the new level (Optional - requires querying state) ---
    // This requires knowing the assetAddress and assetId associated with the UID.
    // You'd typically fetch this using the attestationUID via the SDK query client or getAttestation.
    // Example:
    // const attestationData = await sdk.attestationService.getAttestation(attestationUID);
    // if (attestationData) {
    //   const newLevel = await sdk.attestationService.getDigitalAssetLevel(
    //     attestationData.digitalAssetAddress,
    //     attestationData.digitalAssetId
    //   );
    //   console.log(`Asset level is now: ${newLevel}`);
    //   if (newLevel === 2) {
    //     console.log("Asset promoted to Level 2 (Verified Rights / Licensable)!");
    //   }
    // }

    return verifyTxHash;
  } catch (error) {
    console.error("Error during verification:", error);
    throw error; // Re-throw for higher-level handling
  }
}
```
